JavaWeb了解之SpringMVC篇2

目录
  1. 拦截器
  2. 异常处理
  3. 文件的上传和下载
  4. 注解配置
  5. 国际化

1. 拦截器

类似于Servlet的过滤器,对用户请求进行拦截(在Controller控制器处理请求前、处理完请求后,甚至是渲染视图后)做相应处理。通过拦截器可实现:权限验证、记录请求信息日志、判断用户是否登录等功能。

拦截器使用的是可插拔式设计。如果需要某一拦截器,只需在配置文件中启用该拦截器即可;如果不需要这个拦截器,则只需要在配置文件中取消应用该拦截器即可。

使用步骤:
  1. 创建拦截器类(只需实现HandlerInterceptor接口,并实现该接口的如下3个方法)
    1. boolean preHandle();     
      该方法在控制器方法之前执行。
      返回true时继续向下执行;返回false时中断后续的操作。
    2. void postHandle();   
      该方法会在控制器方法调用之后、解析视图之前执行。
      可以通过该方法对请求域中的Model模型数据和视图做进一步的修改。
    3. void afterCompletion();  
      该方法会在整个请求完成后(即视图渲染结束之后)执行。
      可以通过该方法实现资源清理、日志记录等工作。
    例:
      @Component
      public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle 执行");
            return true;
        }
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle 执行");
        }
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion 执行");
        }
      }
  2. 配置拦截器
    创建拦截器类后,需要在SpringMVC.xml配置文件中对其进行配置才能生效。
    通过使用标签(用来定义一组拦截器)及其子标签(,可任意组合)来配置。
    1. 标签 
      用于定义 一个全局拦截器,对所有的请求进行拦截。
      例:
        
        
          
        
    2. 标签
      用于定义 一个全局拦截器的引用,对所有的请求进行拦截。
      不能单独使用,需要和标签(在标签内外都可以)或@Component注解配合使用(以保证标签配置的拦截器是SpringIoc容器中的一个组件)。
      例:
        
        
        
        
          
        
    3. 标签(子标签:)   
      用于定义 一个指定拦截路径的拦截器(配置拦截器拦截和不需要拦截的请求路径)。
      1.   
        通过path属性 配置拦截的请求路径。
      2. 
        通过path属性 配置不需要拦截的请求路径。
      3. 
        定义一个指定了拦截路径的拦截器。
      例:
        
        
          
          
            
            
            
            
            
            
            
          
        
      注意:在标签中,子标签必须按照上述的配置顺序进行编写,即  的顺序,否则就会报错。

拦截器的执行流程
  1. 单个拦截器的执行流程
    1. 当请求的路径与拦截器拦截的路径相匹配时,程序会先执行拦截器类的preHandle()方法。若该方法返回值为true,则继续向下执行Controller控制器中的方法,否则将不再向下执行。
    2. 执行控制器方法 对请求进行处理。
    3. 执行拦截器的postHandle()方法(在该方法中,可对请求域中的Model模型数据和视图做进一步修改)。
    4. 通过DispatcherServlet的render()方法对视图进行渲染。
    5. 执行拦截器的afterCompletion()方法(在该方法中,可以进行资源清理、日志记录等工作)。
  2. 多个拦截器的执行流程
    实际项目中会存在多个拦截器(来实现不同的功能)。拦截器的执行顺序和拦截器定义在配置文件中的顺序有关(preHandle()方法按照配置顺序执行;PostHandle()方法和afterCompletion()方法则按照配置顺序的反序执行)。
    如果其中有拦截器的preHandle()方法返回了false,则各拦截器方法执行情况如下:
      1. 第一个返回false的preHandle()方法以及它之前的所有拦截器的preHandle()方法都会执行。
      2. 所有拦截器的postHandle()方法都不会执行。
      3. 第一个返回false的preHandle()方法的拦截器(不包括该拦截器)之前的所有拦截器的afterComplation()方法都会执行。
单个拦截器的执行流程

多个拦截器的执行流程(Interceptor1定义在Interceptor2前面)

示例(用户登录权限验证)

需求:
  只有登录后的用户才能访问系统主页,若没有登录就直接访问主页,则拦截器会将请求拦截并跳转到登录页面,同时在登录页面中给出提示信息。
  若用户登陆时,用户名或密码错误,则登录页也会显示相应的提示信息。
  已登录的用户在系统主页点击“退出登录”时,跳转回登录页面。
用户登录流程
===》1. 创建JavaWeb项目(Dynamic Web Project),导入SpringMVC相关的依赖包。
===》2. web.xml


    
    
        CharacterEncodingFilter
        org.springframework.web.filter.CharacterEncodingFilter
        
            encoding
            UTF-8
        
        
            forceResponseEncoding
            true
        
    
    
        CharacterEncodingFilter
        /*
    
    
    
        HiddenHttpMethodFilter
        org.springframework.web.filter.HiddenHttpMethodFilter
    
    
        HiddenHttpMethodFilter
        /*
    
    
    
        dispatcherServlet
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocation
            classpath:springMVC.xml
        
        1
    
    
        dispatcherServlet
        /
    

===》3. 创建springMVC.xml(src目录下)


    
    
    
    
        
        
        
            
                
                    
                        
                        
                        
                        
                        
                        
                    
                
            
        
    
    
    
    
    
    
    
    
    
    
    
        
            
            
            
            
        
    


===》4. 创建User.java(在com.sst.cx.domain下)
package com.sst.cx.domain;
public class User {
    private String userId;
    private String userName;
    private String password;
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String toString() {
        return "User{" +
                "userId='" + userId + '\'' +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
===》5. 创建LoginController.java(在com.sst.cx.controller下)
package com.sst.cx.controller;
import com.sst.cx.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
    // 处理登录请求
    @RequestMapping("/login")
    public String login(User user, HttpServletRequest request) {
        // 验证用户名和密码
        if (user != null && "admin".equals(user.getPassword()) && "admin".equals(user.getUserName())) {
            HttpSession session = request.getSession();
            // 将用户信息放到 session 域中
            session.setAttribute("loginUser", user);
            // 重定向到主页
            return "redirect:/main";
        }
        // 提示用户名或密码错误
        request.setAttribute("msg", "用户名或密码错误");
        return "login";
    }
    // 处理退出请求
    @RequestMapping("/logout")
    public String Logout(User user, HttpServletRequest request) {
        // 设置session失效
        request.getSession().invalidate();
        return "redirect:/";
    }
}
===》6. 创建LoginInterceptor.java(在com.sst.cx.interceptor下)
package com.sst.cx.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginInterceptor implements HandlerInterceptor {
    // 控制器方法执行前,调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object loginUser = request.getSession().getAttribute("loginUser");
        if (loginUser == null) {
            // 未登录,返回登陆页
            request.setAttribute("msg", "您没有权限进行此操作,请先登录!");
            request.getRequestDispatcher("/").forward(request, response);
            return false;
        } else {
            // 放行
            return true;
        }
    }
}

===》7. 创建login.html(在webapp/WEB-INF/templates目录下)



    
    登陆页


用户名:
密码:
===》8. 创建main.html(在webapp/WEB-INF/templates目录下) 系统主页

退出登录 ===》9. 部署到Tomcat,并启动Tomcat 浏览器中访问http://localhost:8080/helloSpringMVC/main

2. 异常处理

应用运行中经常会不可避免地遇到各种可预知的、不可预知的异常,需要对这些异常进行处理以保证程序正常运行。
SpringMVC提供了HandlerExceptionResolver异常处理器接口(可以对控制器方法执行过程中出现的各种异常进行处理)。该接口的常用实现类有以下4个(程序发生异常后默认会按照3 → 2 → 1的顺序,依次使用这3个默认异常处理器对异常进行解析,解析完成则停止)。

1. DefaultHandlerExceptionResolver类(处理 控制器处理请求时出现的异常)
  提供了一个doResolveException()方法(返回类型为ModelAndView),该方法会在控制器方法出现指定异常时,生成一个新的包含了异常信息的ModelAndView对象并替换控制器方法的ModelAndView对象(会将异常转换为相应的code状态码,从而跳转到指定的错误页面来展示异常信息)。
  开发员可以通过状态码来确定发生异常的原因。

===》doResolveException()方法,源码如下
    @Nullable
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
        try {
            if (ex instanceof HttpRequestMethodNotSupportedException) {
                return this.handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException)ex, request, response, handler);
            }
             if (ex instanceof HttpMediaTypeNotSupportedException) {
                return this.handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException)ex, request, response, handler);
            }
            if (ex instanceof HttpMediaTypeNotAcceptableException) {
                return this.handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException)ex, request, response, handler);
            }
            ……
        } catch (Exception var6) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", var6);
            }
        }
        return null;
    }
    
例(在浏览器中直接http://localhost:8080/test使用get方式访问,报错405):
@Controller
public class ExceptionController {
    @RequestMapping(value = "/test", method = RequestMethod.POST)
    public String testDefaultHandlerExceptionResolver() {
        return "success";
    }
}
常见异常 状态码 描述
HttpRequestMethodNotSupportedException 405(Method Not Allowed) HTTP请求方式不支持异常
HttpMediaTypeNotSupportedException 415(Unsupported Media Type) HTTP媒体类型不支持异常
HttpMediaTypeNotAcceptableException 406(Not Acceptable) HTTP媒体类型不可接受异常
BindException 400(Bad Request) 数据绑定异常
MissingServletRequestParameterException 400(Bad Request) 缺少参数异常
ConversionNotSupportedException 500(Internal Server Error) 数据类型转换异常
TypeMismatchException 400(Bad Request) 类型不匹配异常
HttpMessageNotReadableException 400(Bad Request) HTTP消息不可读异常
HttpMessageNotWritableException 500(Internal Server Error) HTTP消息不可写异常
更多的异常及其状态码映射,请参考org.springframework.http.HttpStatus
2. ResponseStatusExceptionResolver类(处理 使用@ResponseStatus注解标注的自定义异常类)
  1. 首先使用@ResponseStatus注解(3个属性)标注一个自定义异常类。
    常用属性:
      1. code属性(设置异常的状态码)value属性的别名,等价于value属性。
      2. value属性(设置异常的状态码)。     
      3. reason属性(设置异常的原因或描述)。  
  2. 当程序运行时发生了这个自定义异常,ResponseStatusExceptionResolver会解析该异常,并将异常信息展示到错误页并返回给客户端。

例:
@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "自定义异常")
public class UserNotExistException extends RuntimeException {
}
@Controller
public class UserController {
    @Resource
    private UserDao userDao;
    @RequestMapping("/login")
    public String login(String userName, Model model) {
        User user = userDao.getUserByUserName(userName);
        if (user == null) {
            throw new UserNotExistException();  // 抛出自定义异常
        }
        return "success";
    }
}
3. ExceptionHandlerExceptionResolver类(处理 控制器类内发生的异常)
  1. 首先在Controller控制器类中使用@ExceptionHandler注解(使用value属性指定要处理的异常)来标注一个处理异常的方法(该方法只能处理该控制器类内的异常)。
  2. 当控制器方法出现指定异常时,调用该控制类中相应的@ExceptionHandler注解标注的方法对异常进行处理。
  3. 如果同一个控制器类内定义了多个使用@ExceptionHandler注解的异常处理方法,则根据继承关系 调用继承深度最浅的异常处理方法 对异常进行处理。
  4. 如果在使用@ControllerAdvice注解标注的类中定义@ExceptionHandler注解标注的方法(可以处理 应用中所有带有@RequestMapping注解的控制器方法 中的异常)则可实现全局异常处理。 

例1
@Controller
public class ExceptionController2 {
    // 控制器方法
    @RequestMapping(value = "/testExceptionHandler")
    public String testExceptionHandler() {
        // 抛出ArithmeticException异常
        System.out.println(10 / 0);
        return "success";
    }
    // 使用@ExceptionHandler注解 定义一个异常处理方法
    @ExceptionHandler(ArithmeticException.class)
    public String handleException(ArithmeticException exception, Model model) {
        // 将异常信息通过Model放到request域中,以便在页面中展示异常信息。
        model.addAttribute("ex", exception);
        return "error";
    }
    // 
    @ExceptionHandler(value = {RuntimeException.class})
    public String handleException2(Exception exception, Model model) {
        model.addAttribute("ex", exception);
        return "error-2";
    }
}

例2(全局异常处理)
@ControllerAdvice
public class ExceptionControllerAdvice {
    @ExceptionHandler
    public String exceptionAdvice(Exception exception, Model model) {
        System.out.println("ExceptionControllerAdvice>>>>>>>>>>>>>>>>>>>");
        model.addAttribute("ex", exception);
        return "error-2";
    }
}
4. SimpleMappingExceptionResolver类(自定义的异常处理器,也能对所有异常进行统一处理)
  1. 创建错误页(在WEB-INF/templates目录下)
  2. 首先在SpringMVC.xml配置文件中,定义SimpleMappingExceptionResolver类型的Bean(配置异常类和错误页面之间的映射关系)。

例
  1. 在webapp/WEB-INF/templates目录下,创建error-hello.html错误页:
    
    
    
        
        Title
    
    
    error出错了!
    

2. 在SpringMVC.xml配置文件中,添加: error-hello

3. 文件的上传和下载

  1. 文件上传
1. 编写Form表单
  form标签的method属性设置为post、enctype属性设置为multipart/form-data(浏览器则会以二进制流的方式对表单数据进行处理,由服务端对文件上传的请求进行解析和处理)。
  至少有一个type属性为file的input标签,该标签的multiple属性可实现同时选择多个文件进行上传。
  例:
    
2. 配置文件解析器(SpringMVC提供了MultipartResolver文件解析器接口来实现文件上传功能) MultipartResolver接口有两个实现类: 1. StandardServletMultipartResolver(仅支持Servlet3.0及以上版本) Servlet内置的上传功能,不需要依赖第三方JAR包。 2. CommonsMultipartResolver(支持Servlet所有版本) 需要导入Apache的commons-fileupload依赖包。 例(CommonsMultipartResolver) 1. 在lib目录中导入依赖包:commons-io-x.x.x.jar、commons-fileupload-xx.xx.xx.jar。 2. 在SpringMVC.xml中,添加 3. 创建控制器方法(添加一个MultipartFile接口类型的形参,该参数封装了被上传文件的信息) 进行文件上传处理 MultipartFile接口是InputStreamSource的子接口,常用的接口方法: 1. byte[] getBytes() 返回 上传文件的内容(以字节数组的形式)。 2. String getContentType() 返回 上传文件的类型。 3. InputStream getInputStream() 返回 上传文件的内容(以input流的形式)。 4. String getName() 返回 请求参数的名称。 5. String getOriginalFillename() 返回 上传文件的原始名(上传的客户端中的文件的名称)。 6. long getSize() 返回 上传文件的大小(单位为字节)。 7. boolean isEmpty() 上传文件是否为空。 8. void transferTo(File destination) 将上传文件保存到目标目录下。 例: @Controller public class FileUploadController { @RequestMapping("/uplaod") public String upload(MultipartFile file) { if (!file.isEmpty()) { return "success"; } return "error"; } }

下载commons-fileupload-xx.xx.xx.jar、commons-io-x.x.x.jar

  1. 文件下载
1. 创建一个File对象(根据文件路径和文件名)
2. 设置响应头(文件的打开方式和下载方式)
3. 控制器方法中返回ResponseEntity对象(需要传入:File对象、响应头、状态码)。
  该对象的作用类似于@ResponseBody注解,都用来直接返回结果对象。
例:见下方示例的DownLoadController控制器

示例(上传和下载)

===》file-upload.html(在webapp/WEB-INF/templates/目录下创建)



    
    Title
    
    


学号:
学生姓名:
年龄:
照片:
===》success.html(在webapp/WEB-INF/templates/目录下创建) Title

学生信息上传成功

学号:
姓名:
年龄:
照片:
点击下载图片
===》MultiFileController.java 上传文件控制器 @Controller public class MultiFileController { // 图片上传 @RequestMapping(value = "/uploadPhoto", method = RequestMethod.POST) @ResponseBody public Map uploadPhoto(MultipartFile photo, HttpServletRequest request) { Map ret = new HashMap(); if (photo == null) { ret.put("type", "error"); ret.put("msg", "选择要上传的文件!"); return ret; } if (photo.getSize() > 1024 * 1024 * 10) { ret.put("type", "error"); ret.put("msg", "文件大小不能超过10M!"); return ret; } // 获取文件后缀 String suffix = photo.getOriginalFilename().substring(photo.getOriginalFilename().lastIndexOf(".") + 1, photo.getOriginalFilename().length()); if (!"jpg,jpeg,gif,png".toUpperCase().contains(suffix.toUpperCase())) { ret.put("type", "error"); ret.put("msg", "请选择jpg、peg、gif、png 格式的图片!"); return ret; } String realPath = request.getServletContext().getRealPath("/upload/"); System.out.println(realPath); File fileDir = new File(realPath); if (!fileDir.exists()) { fileDir.mkdir(); } String filename = photo.getOriginalFilename(); System.err.println("正在上传的图片为:" + filename); String newFileName = UUID.randomUUID() + filename; try { // 将文件保存指定目录 photo.transferTo(new File(realPath + newFileName)); } catch (Exception e) { ret.put("type", "error"); ret.put("msg", "保存文件异常!"); e.printStackTrace(); return ret; } ret.put("type", "success"); ret.put("msg", "上传图片成功!"); ret.put("filepath", "/upload/"); ret.put("filename", newFileName); return ret; } // 提交学生信息 @RequestMapping(value = "/student", method = RequestMethod.POST) public String uploadFile(Student student, Model model) { String fileNameStr = student.getFileNameStr(); String[] split = fileNameStr.split(","); List list = new ArrayList<>(); for (String fileName : split) { list.add(fileName); } student.setPath(list); model.addAttribute("student", student); return "success"; } } ===》DownloadController.java 下载文件控制器 @Controller public class DownLoadController { // 文件下载 @RequestMapping("/downLoadFile") public ResponseEntity downLoadFile(HttpServletRequest request, String fileName) throws IOException { // 得到图片的实际路径 String realPath = request.getServletContext().getRealPath("/upload/" + fileName); // 创建该图片的对象 File file = new File(realPath); // 将图片数据读取到字节数组中 byte[] bytes = FileUtils.readFileToByteArray(file); // 创建 HttpHeaders 对象设置响应头信息 HttpHeaders httpHeaders = new HttpHeaders(); // 设置图片下载的方式和文件名称 httpHeaders.setContentDispositionFormData("attachment", toUTF8String(fileName)); httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK); } // 下载保存时使用中文文件名的字符编码转换方法 public String toUTF8String(String str) { StringBuffer sb = new StringBuffer(); int len = str.length(); for (int i = 0; i < len; i++) { // 取出字符中的每个字符 char c = str.charAt(i); // Unicode码值为0~255时,不做处理 if (c >= 0 && c <= 255) { sb.append(c); } else { // 转换 UTF-8 编码 byte b[]; try { b = Character.toString(c).getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); b = null; } // 转换为%HH的字符串形式 for (int j = 0; j < b.length; j++) { int k = b[j]; if (k < 0) { k &= 255; } sb.append("%" + Integer.toHexString(k).toUpperCase()); } } } return sb.toString(); } } ===》Student.java public class Student { private String stuId; private String stuName; private Integer age; // 用于接收上传的文件 private List photos; // 上传文件名 private String fileNameStr; // 已上传图片的路径集合 private List path; ... 省略setter、getter方法 } /* @RequestMapping(value = "/user", method = RequestMethod.POST) public String login(User user, HttpServletRequest request, Model model) { List newFileNameList = new ArrayList<>(); List photos = user.getPhotos(); for (MultipartFile photo : photos) { String realPath = request.getServletContext().getRealPath("/upload/"); System.out.println(realPath); File fileDir = new File(realPath); if (!fileDir.exists()) { fileDir.mkdir(); } String filename = photo.getOriginalFilename(); System.err.println("正在上传的图片为:" + filename); String newFileName = UUID.randomUUID() + filename; try { // 将文件保存指定目录 photo.transferTo(new File(realPath + newFileName)); } catch (Exception e) { e.printStackTrace(); } newFileNameList.add(newFileName); } System.out.println(user); model.addAttribute("type", "success"); model.addAttribute("user", user); model.addAttribute("filePath", "/upload/"); model.addAttribute("fileNameList", newFileNameList); return "success"; } */

4. 注解配置

除了使用传统的xml文件进行配置外,还可以使用全注解方式(取代web.xml、SpringMVC.xml)进行配置。

1. 使用初始化类替代web.xml
  Servlet容器在启动时,会自动在类路径下查找实现了javax.servlet.ServletContainerInitializer接口的初始化类,来替代web.xml对Servlet容器的上下文进行配置(配置:DispatcherServlet、过滤器)。
  Spring为ServletContainerInitializer接口提供了一个实现类:SpringServletContainerInitializer类,其部分源码如下:
    // @HandlesTypes注解:获取所有实现了WebApplicationInitializer接口的类,并赋值给onStartup()方法的webAppInitializerClasses参数,在onStartup()方法中调用WebApplicationInitializer实现类中的方法来实现对DispatcherServlet和SpringMVC的配置工作。
    @HandlesTypes({WebApplicationInitializer.class})
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        public SpringServletContainerInitializer() {
        }
        public void onStartup(@Nullable Set> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
            ……
        }
    }
  Spring为WebApplicationInitializer接口提供了一个实现类:AbstractAnnotationConfigDispatcherServletInitializer类,其常用方法如下:
    1. protected abstract Class[] getRootConfigClasses();    
      用于设置Spring的配置类。
    2. protected abstract Class[] getServletConfigClasses();     
      用于设置SpringMVC的配置类。
    3. protected abstract String[] getServletMappings();    
      用于指定DispatcherServelt的映射规则(即:web.xml中的url-pattern)。
    4. protected Filter[] getServletFilters()   
      用于添加各种过滤器(Filter)。
  因此,开发员只需创建一个继承自AbstractAnnotationConfigDispatcherServletInitializer的类 并实现以上4个方法。

例
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    // 设置Spring的配置类
    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }
    // 设置SpringMVC的配置类
    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }
    // 为DispatcherServlet指定映射规则(即:web.xml中的url-pattern)
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
    // 添加过滤器
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceResponseEncoding(true);
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        return new Filter[]{characterEncodingFilter,hiddenHttpMethodFilter};
    }
}
2. 使用@Configuration注解标注的普通类(被称为配置类)替代Spring的配置文件(Ioc容器)
  在配置类中,可以定义多个使用@Bean注解标注的方法(等价于Spring配置文件中的标签)将指定的Java对象以Bean的形式交由IoC容器管理。 

例
@Configuration
public class SpringConfig {
    // 定义Bean
    // 方法名相当于标签的id属性;方法的返回值类型就相当于标签的class属性;
    // 若方法中存在形参,则该参数对象通常为Spring容器中的组件,Spring会按照类型或参数名称注入该参数对象。
    @Bean
    public Student student(){
        Student student = new Student();
        student.setStuId("1001");
        student.setStuName("张三");
        student.setAge(12);
        return student;
    }
}
等价于xml文件形式配置:
    
        
        
        
    
3. 使用@Configuration注解标注的普通类(被称为配置类)替代SpringMVC的配置文件
  SpringMVC的配置组件(组件扫描、开启注解、视图解析器、拦截器、异常解析器、类型转换器和格式化器、文件上传解析器等)在配置类中的配置方式不同(大致分为3种方式):
    1. 实现WebMvcConfigurer接口(在SpringBoot2.0之前使用的是已废弃的WebMvcConfigurerAdapter抽象类)
      通过在实现WebMvcConfigurer接口的配置类(使用@Configuration注解标注的普通类)中实现对应的接口方法来对SpringMVC部分组件(静态资源、拦截器、视图控制器、异常解析器、类型转换器和格式化器)进行配置。
      接口中定义的常见方法的说明见下面。
      例:
      // 将静态资源文件交给默认Servlet处理
      @Override
      public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
          configurer.enable();
      }
      // 配置拦截器(对请求进行拦截处理)
      @Override
      public void addInterceptors(InterceptorRegistry registry) {
          MyInterceptor myInterceptor = new MyInterceptor();
          registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/");
      }
      // 配置视图控制器(路径<-->页面)
      @Override
      public void addViewControllers(ViewControllerRegistry registry) {
          registry.addViewController("/").setViewName("user");
      }
      // 配置异常解析器(异常<-->页面)
      @Override
      public void configureHandlerExceptionResolvers(List resolvers) {
          SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
          Properties prop = new Properties();
          prop.setProperty("java.lang.Exception", "error");
          // 设置异常映射
          exceptionResolver.setExceptionMappings(prop);
          // 设置共享异常信息的键
          exceptionResolver.setExceptionAttribute("ex");
          resolvers.add(exceptionResolver);
      }
      // 配置类型转换器和格式化器
      @Override
      public void addFormatters(FormatterRegistry registry) {
          MyDateConverter myDateConverter = new MyDateConverter();
          registry.addConverter(myDateConverter);
      }
    2. 使用@EnableWebMvc、@ComponentScan等注解(标注 配置类)
      1. @ComponentScan("com.sst.cx")  
        等价于
        开启组件扫描(会扫描包路径下所有使用@Controller注解的类)。
      2. @EnableWebMvc
        等价于        
        开启SpringMVC注解驱动。
    3. 使用@Bean注解(在配置类中)
      1. 配置Thymeleaf视图解析器
        // 模板解析器
        @Bean
        public ITemplateResolver templateResolver() {
            WebApplicationContext webApplicationContext =
                    ContextLoader.getCurrentWebApplicationContext();
            // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过 WebApplicationContext获取
            ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());
            templateResolver.setPrefix("/WEB-INF/templates/"); //  视图前缀
            templateResolver.setSuffix(".html");
            templateResolver.setCharacterEncoding("UTF-8");
            templateResolver.setTemplateMode(TemplateMode.HTML);
            return templateResolver;
        }
        // 模板引擎(注入模板解析器)
        @Bean
        public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
            SpringTemplateEngine templateEngine = new SpringTemplateEngine();
            templateEngine.setTemplateResolver(templateResolver);
            return templateEngine;
        }
        // 视图解析器(注入模板引擎)
        @Bean
        public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
            ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
            viewResolver.setCharacterEncoding("UTF-8");
            viewResolver.setTemplateEngine(templateEngine);
            return viewResolver;
        }
        等价于 xml文件形式配置Thymeleaf视图解析器。
      2. 配置文件上传解析器
        // 配置文件上传解析器
        @Bean
        public CommonsMultipartResolver multipartResolver() {
            CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
            commonsMultipartResolver.setDefaultEncoding("UTF-8");
            commonsMultipartResolver.setMaxUploadSize(1024*1024*10);
            return commonsMultipartResolver;
        }
        等价于 xml文件形式配置文件上传解析器。

例
@Configuration
@ComponentScan("com.sst.cx")
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
  方式1中示例(实现WebMvcConfigurer接口方法)
  方式3中示例(@Bean注解)
}
常用的WebMvcConfigurer接口方法 描述(返回值都是void)
configurePathMatch HandlerMappings路径的匹配规则
configureContentNegotiation 内容协商策略(一个请求路径返回多种数据格式)。
configureAsyncSupport 配置异步请求处理相关参数
configureDefaultServletHandling (将静态文件交给Servlet容器内置的默认Servlet处理)实现静态文件可以像Servlet一样被访问。
addFormatters 配置Converter转换器、Formatter格式化器。
addInterceptors 配置拦截器(对请求进行拦截处理)。
addResourceHandlers 添加或修改静态资源映射(设置默认的静态资源目录)。
addCorsMappings 配置跨域请求相关参数
addViewControllers 添加和业务逻辑无关(直接简单跳转,不传递数据)的跳转(路径<-->页面)。
configureViewResolvers 将Controller返回的视图名转换为具体的视图页面。
addArgumentResolvers 自定义Controller方法参数类型,不会覆盖默认的处理(想覆盖,可直接去配置RequestMappingHandleAdapter)。
addReturnValueHandlers 自定义Controller返回值类型,不会覆盖默认的处理(想覆盖,可直接去配置RequestMappingHandleAdapter)。
configureMessageConverters 配置默认的消息转换器(转换 HTTP请求/响应)
extendMessageConverters 扩展消息转换器(通过此方式扩展则会新增;通过直接添加的方式会使默认的消息转换器列表失效;)
configureHandlerExceptionResolvers 配置异常处理器(异常<-->页面)。
extendHandlerExceptionResolvers 扩展异常处理器列表

5. 国际化

为不同的国家/语言提供相应的页面和数据。

使用步骤:
  1. 在SpringMVC.xml配置文件中,添加
    
    
        
        
        
        
        
    
    
        
    
    
        
            
        
    

  2. 创建国际化资源文件(在类路径下创建)
    文件名格式为:基本名_语言_国家.properties(国际化资源文件名称必须严格按照其命名格式进行命名,否则解析时会出错)。
    IDEA:打开任意一个国际化资源文件,切换为ResourceBundle模式(需要安装ResourceBundle插件),然后点击“+”号创建所需的国际化属性(需要进行国际化的字段)。
    例(IDEA会自动识别国际化资源文件并自动添加Resouce Bundle目录下)
      messages.properties:默认
        userName=用户名
        password=密码
      messages_zh_CN.properties:中文时生效
        userName=用户名
        password=密码
      messages_en_US.properties:英语时生效
        userName=userName
        password=password

  3. 在页面中获取国际化内容;
    

4. 创建控制器方法来实现手动切换语言。 英文 中文 @Controller public class I18nController { @Resource private ResourceBundleMessageSource messageSource; // 切换语言环境 @RequestMapping("/localeChange") public String localeChange(Locale locale) { String userName = messageSource.getMessage("userName", null, locale); String password = messageSource.getMessage("password", null, locale); System.out.println(userName + "----" + password); return "user"; } }

你可能感兴趣的:(JavaWeb了解之SpringMVC篇2)