一、响应数据和结果视图

1.1 返回值分类

1.1.1 字符串

  • controller中的方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。

    • 物理路径为/WEB-INF/pages/success.jsp
    @RequestMapping("/testReturnString")
    public String test01(){
        System.out.println("测试成功");
        return "success";
    }

1.1.2 void

  • Servlet原始API可以作为控制器中方法的参数

    • 转发forward

      @RequestMappint("/testReturnVoid")
      public void testReturnVoid(HttpServletRequest request, HttpServletResponse response){
          request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
      }
    • 重定向

      @RequestMappint("/testReturnVoid")
      public void testReturnVoid(HttpServletRequest request, HttpServletResponse response){
          response.sendRedirect("testReturnString");
      }
    • 响应json结果

      @RequestMappint("/testReturnVoid")
      public void testReturnVoid(HttpServletRequest request, HttpServletResponse response){
          response.setCharacterEncoding("utf-8");             
          response.setContentType("application/json;charset=utf-8"); 
          response.getWriter().write("json串");
      }

1.1.3 ModelAndView

  • ModelAndView是SpringMVC为我们提供的一个对象,也可作为控制器方法的返回值。

    @RequestMapping("/testReturnModelAndView") 
    public ModelAndView testReturnModelAndView() { 
        ModelAndView mv = new ModelAndView(); 
        mv.addObject("username", "张三"); 
        mv.setViewName("success");
        return mv;
    }

1.2 转发和重定向

1.2.1 forward转发

  • controller方法在提供了String类型的返回值之后,默认就是请求转发。
  • 返回值:forward:url,其中url为实际视图的地址

    @RequestMapping("/testForward")
    public String testForward(){
        System.out.println("转发");
        return "forward:/WEB-INF/pages/success.jsp";
    }

1.2.2 redirect重定向

  • 返回值:redirect:url
  • 如果重定向到jsp页面,这个jsp页面不能写在WEB-INF目录中,不然是找不到的。

1.3 ResponseBody响应json数据

  • @ResponseBody注解将Controller方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据,如json、xml等,并Response给客户端。
  • 需要导包:

    1. jackson-annotations-2.9.0.jar
    2. jackson-databind-2.9.0.jar
    3. jackson-core-2.9.0.jar
  • 代码示例

    • 前端发送ajax异步请求

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>response</title>
          <script src="js/jquery.min.js"></script>
          <script>
              $(function () {
                 $("#btn").click(function () {
                     $.ajax({
                         url:"user/testAjax",
                         contentType:"application/json;charset=UTF-8",
                         //data:{"username":"tom", "password":"123", "age":23},
                         data:'{"username":"tom","password":"123","age":23}',
                         dataType:"json",
                         type:"post",
                         success:function(data){
                             //服务器响应回来的数据显示
                             alert(data);
                             alert(data.username);
                         }
                     });
                 });
              });
          </script>
      </head>
      <body>
      <button id="btn">发送ajax请求</button>
      </body>
      </html>
      
    • 两种方式:

      1. 传的是json字符串

        contentType:"application/json;charset=UTF-8",
        data:'{"username":"tom","password":"123","age":23}',
   - 必须设置`contentType`
   - data是字符串类型

2. 传的是表单数据类型
data:{"username":"tom", "password":"123", "age":23},
  • controller代码

    1. 接收的是json字符串

      @RequestMapping("/testAjax")
      public @ResponseBody User testAjax(@RequestBody User user){
       System.out.println("testAjax执行了");
       System.out.println(user);
       user.setUsername("alex");
       return user;
      }
   - 形参内必须加上`@RequestBody`注解,因为解析的是字符串

2. 接收的是表单数据
    @RequestMapping("/testAjax")
    public @ResponseBody User testAjax(User user){
        System.out.println("testAjax执行了");
        System.out.println(user);
        user.setUsername("alex");
        return user;
    }
   - 形参内没有`@RequestBody`注解

二、SpringMVC实现文件上传

2.1 文件上传的回顾

2.1.1 文件上传的必要前提

  1. form表单的enctype取值必须是:multipart/form-data

    1. enctype:表单请求正文的类型
  2. method一定要是post
  3. 提供一个文件选择域:<input type="file">

2.1.2 借助第三方组件实现文件上传

  1. commons-fileupload-1.3.1.jar
  2. commons-io-2.4.jar

2.2 传统方式上传文件

2.2.1 导包

  1. commons-fileupload-1.3.1.jar
  2. commons-io-2.4.jar

2.2.2 前端jsp页面

    <h2>传统方式文件上传</h2>
    <form action="user/fileUpload" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="file">
        <input type="submit" value="上传文件">
    </form>

2.2.3 编写控制器方法

    /**
     * 传统方式文件上传
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping("/fileUpload")
    public String fileUpload(HttpServletRequest request) throws Exception {
        //设置上传位置
        String path = request.getSession().getServletContext().getRealPath("/upload/");
        //判断该路径是否存在
        File file = new File(path);
        if (!file.exists()) {
            //如果不存在,创建文件夹
            file.mkdirs();
        }
        //解析request对象,获取上传文件项
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        //解析request
        List<FileItem> items = upload.parseRequest(request);
        //遍历
        for (FileItem item : items) {
            //判断当前item对象是否为上传文件项
            if (item.isFormField()) {
                //为普通表单项
            } else {
                //为上传文件项
                //获得文件名
                String filename = item.getName();
                String uuid = UUID.randomUUID().toString().replace("-", "");
                //使得上传文件名是唯一的
                filename = uuid + "_" + filename;
                item.write(new File(path, filename));
                //删除临时文件
                item.delete();
            }
            System.out.println(path);
        }
        return "success";
    }

2.2.4 配置文件解析器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.ruki"></context:component-scan>

    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"></property>
    </bean>

    <mvc:resources location="/js/" mapping="/js/**"></mvc:resources>

    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

2.3 SpringMVC跨服务器上传文件

  • 分服务器的目的:在实际开发中,会有很多处理不同功能的服务器,如

    1. 应用服务器:负责部署应用
    2. 数据库服务器:运行数据库
    3. 缓存和消息服务器:负责处理大并发访问的缓存和消息
    4. 文件服务器:负责存储用户上传文件的服务器。

2.3.1 准备两个tomcat服务器

  1. 其中一个服务器部署的web工程,专用来存放图片。(需要修改端口号)
  2. 对文件服务器的web.xml文件进行修改,允许读写操作!

    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>readonly</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

2.3.2 导包

  1. jersey-client-1.18.1.jar
  2. jersey-core-1.18.1.jar
  3. commons-fileupload-1.3.1.jar
  4. commons-io-2.4.jar

2.3.3 编写控制器方法

@Controller("fileUploadController2") 
public class FileUploadController2 { 
    public static final String FILESERVERURL = "http://localhost:9090/day06_spring_image/uploads/"; 
    /** 
    * 文件上传,保存文件到不同服务器 
    */ 
    @RequestMapping("/fileUpload2") 
    public String testResponseJson(String picname,MultipartFile uploadFile) throws Exception{ 
        //定义文件名 
        String fileName = ""; 
        //1.获取原始文件名 
        String uploadFileName = uploadFile.getOriginalFilename(); 
        //2.截取文件扩展名 
        String extendName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1, uploadFileName.length()); 
        //3.把文件加上随机数,防止文件重复 
        String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase(); 
        //4.判断是否输入了文件名 
        if(!StringUtils.isEmpty(picname)) { 
            fileName = uuid+"_"+picname+"."+extendName; 
        }else { 
            fileName = uuid+"_"+uploadFileName; 
        } 
        System.out.println(fileName); 
        //5.创建sun公司提供的jersey包中的Client对象 
        Client client = Client.create(); 
        //6.指定上传文件的地址,该地址是web路径 
        WebResource resource = client.resource(FILESERVERURL+fileName); 
        //7.实现上传 
        String result = resource.put(String.class,uploadFile.getBytes()); 
        System.out.println(result); 
        return "success"; 
    }
}

2.3.4 前端jsp页面

<form action="fileUpload2" method="post" enctype="multipart/form-data"> 
    名称:<input type="text" name="picname"/><br/> 
    图片:<input type="file" name="uploadFile"/><br/> 
    <input type="submit" value="上传"/> 
</form>

2.3.5 配置文件解析器

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"></property>
    </bean>

三、SpringMVC中的异常处理

3.1 异常处理流程

3.2 实现步骤

3.2.1 自定义异常

package com.ruki.exception;

public class SysException extends Exception {
    private String message;

    public SysException(String message) {
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

3.2.2 错误提示页面

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>error</title>
</head>
<body>
    ${errorMsg}
</body>
</html>

3.2.3 自定义异常处理器

package com.ruki.exception;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SysExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        SysException e = null;
        if(ex instanceof SysException){
            e = (SysException)ex;
        } else{
            e = new SysException("系统正在维护");
        }
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg", e.getMessage());
        mv.setViewName("error");

        return mv;
    }
}

3.2.4 配置异常处理器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.ruki"></context:component-scan>

    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <bean id="sysExceptionResolver" class="com.ruki.exception.SysExceptionResolver"></bean>

    <mvc:annotation-driven></mvc:annotation-driven>
</beans>
  • 这句话最重要
<bean id="sysExceptionResolver" class="com.ruki.exception.SysExceptionResolver"></bean>

四、SpringMVC中的拦截器

  • Spring MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。 用户可以自己定义一些拦截器来实现特定的功能。

4.1 拦截器interceptor和过滤器filter的区别

  • 过滤器是servlet规范中的一部分,任何java web工程都可以使用。
  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
  • 过滤器url-pattern中配置了<font color="red">/*</font>之后,可以对所有要访问的资源拦截。
  • 拦截器它是只会拦截访问的控制器方法,如果访问的是jsp、html、css、image或者js是不会进行拦截的。
  • 我们要想自定义拦截器, 要求必须实现:HandlerInterceptor接口。

4.2 自定义拦截器的步骤

4.2.1 自定义拦截器类并实现HandlerInterceptor接口

  • preHandle():预处理
  • postHandle:后处理
  • afterCompletion:最终处理
package com.ruki.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor111.....执行前");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor111.....执行后");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor111最后执行");
    }
}

4.2.2 配置拦截器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.ruki"></context:component-scan>

    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*"/>
            <bean class="com.ruki.interceptor.MyInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*"/>
            <bean class="com.ruki.interceptor.MyInterceptor2"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

    <mvc:annotation-driven></mvc:annotation-driven>
</beans>
  • 其中最重要的部分:
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*"/>
            <bean class="com.ruki.interceptor.MyInterceptor2"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

4.3 拦截器的细节

4.3.1 拦截器的放行

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor111.....执行前");
        return true;
    }
  • 当返回值为true时,才是放行。

4.3.2 拦截器中方法的说明

  • preHandle():预处理

    • 按照拦截器定义顺序调用
  • postHandle:后处理

    • 按照拦截器定义逆序调用
    • 在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用
  • afterCompletion:最终处理

    • DispatcherServlet 完全处理完请求后被调用
    • 可以在该方法中进行一些资源清理的操作

4.3.3 拦截器的作用路径

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*"/>
            <bean class="com.ruki.interceptor.MyInterceptor2"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
  • <mvc:mapping path="/**" />

    • 用于指定对拦截的url
  • <mvc:exclude-mapping path=""/>

    • 用于指定排除的url

4.3.4 拦截器的执行顺序

Last modification:September 30th, 2019 at 07:40 pm