• Java框架之SpringMVC 04-视图解析-Spring表单-JSON-上传下载


    SpringMVC

    视图解析

      请求处理方法(controller方法)执行完成后,最终返回一个 ModelAndView 对象,即使出现异常也会返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象的视图,由视图解析器解析视图,然后,进行页面的跳转。

      Spring MVC 借助视图解析器ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart等各种表现形式的视图

    视图View

      视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户

        1. 将数据存放到域中   request.setAttribute(name,value)

        2. 转发|重定向       rd.forward(request,response);

      为了实现视图模型和具体实现技术的解耦,Spring 在 org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口

      视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题

    常用的视图实现类

      转发视图:InternalResourceView

      转发视图:JstlView 需导入Jstl的jar包,适配器会自动调用此解析器,此解析器继承了InternalResourceView

        若使用 JSTL 的 fmt 标签则需要在 SpringMVC 的配置文件中装配标准资源文件bean

      重定向视图:RedirectView

        一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理

        如果返回的字符串中带 forward: 或 redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理

        在返回值中 return "redirect:/success_redirect.jsp";解析器会自动重定向到此页面,不需在前面加工程路径名RedirectView会自动帮我们追加上

    注意

    转发:访问 WEB-INF 下路径时只允许当前请求为GET或POST请求模式的才能转发成功,(也就是浏览器只支持GET、POST请求的转发)默认携带当前的请求方式发起转发请求。

       访问 Controller 内部路径时必须加上前缀 forward: 同样携带当前的请求方式发起请求,必须有对应的请求方式的路径

    重定向:必须先加上前缀 redirect: 访问 WEB-INF 下的路径不被允许,默认用 GET 方法发起新的请求。

        访问 Controller 内部路径时同样只能重定向到GET请求方式的路径

    视图解析器ViewResolver

      SpringMVC 为逻辑视图名的解析提供了不同的策略,可以在 SpringMVC 上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。通过反射原理

      视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象

        url= getPrefix() + viewName + getSuffix()

      每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order  越小优先级越高。

       JSP 是最常见的视图技术,可以使用默认的 InternalResourceViewResolve 作为视图解析器

       BeanNameViewResolver:将逻辑视图名解析为一个 Bean , Bean 的 id 等于逻辑视图名

    Spring表单标签

      SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显

       引入标签库

    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

    form 标签

      <form:form> 标签  可以通过 modelAttribute 属性指定绑定的模型属性,若没有指定该属性,则默认从 request 域对象中读取 command 属性的表单 bean,如果该属性值也不存在,则会发生错误。

      SpringMVC 提供了多个表单组件标签用以绑定表单字段的属性值,如 <form:input/>(同html标签中 input type="text"),它们的共有属性:

      • path表单字段,对应 html 元素的 name 属性,支持级联属性
      • htmlEscape:是否对表单值的 HTML 特殊字符进行转换,默认值为 true
      • cssClass:表单组件对应的 CSS 样式类名
      • cssErrorClass:表单组件的数据存在错误时,采取的 CSS 样式

      form:input、form:password、form:hidden、form:textarea:对应 HTML 表单的 text、password、hidden、textarea 标签

      form:radiobutton:单选框组件标签,当表单 bean 对应的属性值和 value 值相等时,单选框被选中

      form:radiobuttons:单选框组标签,用于构造多个单选框

      • items:可以是一个 List、String[] 或 Map
      • itemValue:指定 radio 的 value 值。可以是集合中 bean 的一个属性值
      • itemLabel:指定 radio 的 label 值
      • delimiter:多个单选框可以通过 delimiter 指定分隔符

      form:checkbox:复选框组件。用于构造单个复选框

      form:checkboxs:用于构造多个复选框。使用方式同 form:radiobuttons 标签

      form:select:用于构造下拉框组件。使用方式同 form:radiobuttons 标签

      form:option:下拉框选项组件标签。使用方式同 form:radiobuttons 标签

      form:errors:显示表单组件或数据校验所对应的错误

      • <form:errors path= “*” /> :显示表单所有的错误
      • <form:errors path= “user*” /> :显示所有以 user 为前缀的属性对应的错误
      • <form:errors path= username /> :显示特定表单对象属性的错误
    //修改功能需要增加绝对路径,相对路径会报错,路径不对
    <form:form action="${pageContext.request.contextPath }/emp" method="POST" modelAttribute="employee(command)">
        LastName:<form:input path="lastName"/><br><br>
        Email:<form:input path="email"/><br><br>
        Gender:<form:radiobuttons path="gender" items="${genders }"/><br><br>
        Dept:
        <form:select path="department.id" items="${depts }" 
                 itemLabel="departmentName" itemValue="id">
        </form:select>
        <br><br>
        <input type="submit" value="添加员工信息">
    </form:form>

    通过jQuery转换为DELETE请求

      REST风格代码,要求删除功能,必须以DELETE方式提交。解决方案

        1. 准备一个以DELETE方式提交的form表单

        2. 通过单击事件为准备好的form表单action属性赋值。

        3. 触发表单的submit事件

    $(function(){
      $(".delete").click(function(){
        var href = $(this).attr("href");
        $("form").attr("action",href).submit();
        return false ;
      });
    });

    SpringMVC 处理静态资源

      若将 DispatcherServlet 请求映射配置为 /, 则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理, 因找不到对应处理器将导致错误。从而无法加载静态资源

      解决: 需要在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/> 它将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查,如果发现是静态资源的请求,就会由此处理器处理

        并且还需要配置<mvc:annotation-driven />,因为只配置上面一个所有请求又全部只由默认处理器来处理请求了

    底层原理:Tomcat解析Servlet优先级问题

      程序员定义的 Servlet优先级大于Tomcat自己的Servlet

      URL中default-servlet配置 "*.jsp" 大于 "/" 的配置。

    处理JSON和下载

    HttpMessageConverter<T>

      HttpMessageConverter<T> 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息

      当控制器处理方法使用到 @RequestBody/@ResponseBody 或 HttpEntity<T>/ResponseEntity<T> 时, Spring 首先根据请求头或响应头的 Accept 属性选择匹配的 HttpMessageConverter,  进而根据参数类型或泛型类型的过滤得到匹配的 HttpMessageConverter, 若找不到可用的 HttpMessageConverter 将报错 406

      HttpMessageConverter<T> 可将请求信息转化并绑定到(controller)处理方法的入参中或将响应结果转为对应类型的响应信息

    SpringMVC处理 json

      1) jackson-annotations-2.1.5.jar

        jackson-core-2.1.5.jar

        jackson-databind-2.1.5.jar

      2)需要在配置文件设置 <mvc:annotation-driven />

        如此可将适配器AnnotationMethodHandlerAdapter升级为:RequestMappingHandlerAdapter 而 RequestMappingHandlerAdapter 适配器中存在MappingJackson2HttpMessageConverter

      3)@RequestBody / @ResponseBody 在处理方法上进行标注

          @RequestBody:是将Http请求正文插入到处理方法中,修饰目标方法的入参

          @ResponseBody:是将内容或对象作为Http响应正文返回去

    将user对象转为json对象返回,注意ajax设置dataType:"json"类型

    @ResponseBody
    @RequestMapping(value = "/json",method = RequestMethod.GET)
    public User json(String string){
        return user;
    }

    异步请求

                $("#username1").change(function () {
                   var username = $("#username1").val();
                   var dat = {
                       "username":username,
                       "_method":"PUT",
                   };
                   $.ajax({
                       url:"${pageContext.request.contextPath}/login",
                       type:"POST",
                       data:dat,
                       dataType:"json",
                       success:function (data) {
                           alert(data.name);
                       },
                       error:function () {
                           alert("请求失败");
                       }
                   });
                });

      HttpEntity<T>        作为处理方法的入参获取文件大小请求头等

      ResponseEntity<T>   作为处理方法的返回值,返回客户端要下载的文件资源,实现文件下载功能

     下载

     @RequestMapping(value = "/downLoad",method = RequestMethod.GET)
        public ResponseEntity<byte[]> testDownLoad(HttpServletRequest request,HttpServletResponse response) throws IOException {
            ResponseEntity<byte[]> responseEntity = null;
            //1.获取到download文件的真实路径(推荐先放在项目根目录下测试_downLoad为文件名)
            String path = request.getServletContext().getRealPath("/downLoad");
            //在请求体中获取文件名
            String fileName = request.getParameter("fileName");
            //2.通过真实文件路径创建File对象(File.separator为当前系统文件分隔符)
            File file = new File(path + File.separator + fileName);
            //3.创建文件输入流,将要下载的文件读取到程序中
            FileInputStream fileInputStream = new FileInputStream(file);
            byte[] bytes = new byte[fileInputStream.available()];
            //将文件一次性全部读取到bytes中
            fileInputStream.read(bytes);
            //解决 文件名 中文乱码问题
            String header = request.getHeader("User-Agent");
            if(header != null && header.contains("Firefox")) {
                fileName = "=?utf-8?B?"+new BASE64Encoder().encode(fileName.getBytes("utf-8"))+"?=";
            }else {
                fileName = URLEncoder.encode(fileName, "UTF-8");
            }
            //创建响应头
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.add("Content-Disposition", "attachment; filename="+fileName);
            //返回资源(HttpStatus.OK=200)
            responseEntity = new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK);
            fileInputStream.close();
            return responseEntity;
        }

    文件上传

      Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。实现类:CommonsMultipartResolver 

      Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,需在上下文中配置 MultipartResolver

    配置 MultipartResolver

      defaultEncoding: 必须和用户 JSP 的 pageEncoding 属性一致,以便正确解析表单的内容,为了让 CommonsMultipartResolver 正确工作,必须先将 Commons-fileupload 及 Commons-io 的 jar 包添加到类路径下。

        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="defaultEncoding" value="UTF-8"></property>
            <property name="maxUploadSize" value="10240000"></property>
        </bean>

      MultipartResolver 用于处理文件上传,当收到请求时 DispatcherServlet 的 checkMultipart() 方法会调用 MultipartResolver 的 isMultipart() 方法判断请求中是否包含文件。如果请求数据中包含文件,则调用 MultipartResolver 的 resolveMultipart() 方法对请求的数据进行解析,然后将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest (继承了 HttpServletRequest) 对象中,最后传递给 Controller

    上传文件

    <form action="${pageContext.request.contextPath}/upLoad" method="post" enctype="multipart/form-data">
        需上传文件:<input type="file" name="file">
        <input type="submit">
    </form>
        @RequestMapping(value = "/upLoad",method = RequestMethod.POST)
        public String upLoad(@RequestParam("file")MultipartFile multipartFile,HttpServletRequest request) throws IOException {
            //1.获取upload的真实路径
            String path = request.getServletContext().getRealPath("/upLoad");
            //如果此路径不存在则创建此目录
            File file1 = new File(path);
            if(!file1.exists()){
                file1.mkdir();
            }
            //2.获取要上传的文件名
            String filename = multipartFile.getOriginalFilename();
            //3.创建上传file
            File file = new File(path + File.separator + filename);
            //4.实现文件上传
            multipartFile.transferTo(file);
            return "home";
        }

    多文件上传

     

  • 相关阅读:
    Azkaban的使用
    Azkaban安装
    Kafka 启动失败,报错Corrupt index found以及org.apache.kafka.common.protocol.types.SchemaException: Error reading field 'version': java.nio.BufferUnderflowException
    Kafka 消费者设置分区策略及原理
    Kafka利用Java API自定义生产者,消费者,拦截器,分区器等组件
    zookeeper群起总是有那么几个节点起不来的问题解决
    flume 启动agent报No appenders could be found for logger的解决
    Flume 的监控方式
    Flume 自定义 组件
    Source r1 has been removed due to an error during configuration java.lang.IllegalArgumentException: Required parameter bind must exist and may not be null & 端口无法连接
  • 原文地址:https://www.cnblogs.com/Open-ing/p/12228444.html
Copyright © 2020-2023  润新知