Spring MVC进阶知识

1. Spring MVC配置

1.1 自定义DispatcherServlet配置

覆写AbstractAnnotationConfigDispatcherServletInitializer的customizeRegistration()方法

@Override
protected void customizeRegistration(Dynamic registration) {
  registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
}

1.2 添加servlet、filter

实现WebApplicationInitializer接口

注册一个servlet:

package com.myapp.config;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import com.myapp.MyServlet;

public class MyServletInitializer implements WebApplicationInitializer {
  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
    Dynamic myServlet = servletContext.addServlet("myServlet", MyServlet.class);
    myServlet.addMapping("/custom/**"); 
  }
}

注册一个filter:

public class MyServletInitializer implements WebApplicationInitializer {
  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
    javax.servlet.FilterRegistration.Dynamic filter =
      servletContext.addFilter("myFilter", MyFilter.class);
    filter.addMappingForUrlPatterns(null, false, "/custom/*");
  }
}

WebApplicationInitializer适用于通用的添加servlet、filter、listener。

覆写AbstractAnnotationConfigDispatcherServletInitializer抽象类的getServletFilters()方法也可以添加filter:

@Override
protected Filter[] getServletFilters() {
    return new Filter[] { new MyFilter() };
}

1.3 在web.xml中声明DispatcherServlet

Spring MVC进阶知识_第1张图片
image.png
Spring MVC进阶知识_第2张图片
定义DispatcherServlet配置文件的位置

在web.xml中使用Java配置类:


Spring MVC进阶知识_第3张图片
image.png

Spring MVC进阶知识_第4张图片
image.png

2. 处理multipart form

在提交表单的时候,有时候会附带上传文件,文件会以二进制的形式提交。
multipart form回将提交的数据分成几个独立的部分,每个部分拥有自己的属性,自己的类型。

multipart request body样例:


Spring MVC进阶知识_第5张图片
multipart request body

2.1 配置multipart解析器

实现MultipartResolver。

Spring提供了两种MultipartResolver实现:

  1. CommonsMultipartResolver 使用Jakarta Commons FileUpload来解析multipart请求
  2. StandardServletMultipartResolver 依赖Servlet 3.0对于multipart请求的支持(since Spring 3.1)
使用Servlet3.0来解析multipart请求
@Bean
public MultipartResolver multipartResolver() throws IOException {
  return new StandardServletMultipartResolver();
}

配置一些对于文件的上传的属性:
(1) 如果是配置DispatcherServlet时实现了WebApplicationInitializer接口

DispatcherServlet ds = new DispatcherServlet();
Dynamic registration = context.addServlet("appServlet", ds);
registration.addMapping("/");
registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));

(2) 如果在配置DispatcherServlet时继承了AbstractAnnotationConfigDispatcherServletInitializer或AbstractDispatcherServletInitializer,那就覆写customizeRegistration()方法

@Override
protected void customizeRegistration(Dynamic registration) {
  registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
}

MultipartConfigElement的构造方法的参数作用:

. 设置文件的临时位置
. 限定上传文件的最大size(in bytes),默认是没有上限的
. 配置整个multipart请求的最大size(in bytes),默认是没有上限的
. 限定一个上传的文件不写入临时位置,而直接写入到磁盘的最大size(in bytes),这个值默认是0,也就是说默认情况下,所有的文件都会写到磁盘上

/**
* 单个文件不能超过2MB,整个请求不能超过4MB,所有文件都要直接写到磁盘上
*/
@Override
protected void customizeRegistration(Dynamic registration) {
  registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads", 2097152, 4194304, 0));
}

(3)如果在配置DispatcherServlet时使用了web.xml,就使用元素就好了


  appServlet
  
    org.springframework.web.servlet.DispatcherServlet
  
  1
  
    /tmp/spittr/uploads
    2097152
    4194304
  

配置JAKARTA COMMONS FILEUPLOAD Multipart解析器
@Bean
public MultipartResolver multipartResolver() throws IOException {
  CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
  multipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spittr/uploads"));
  multipartResolver.setMaxUploadSize(2097152);
  multipartResolver.setMaxInMemorySize(0);
  return multipartResolver;
}

2.2 处理multipart请求

最常用的方法是在controller的方法参数加上注解@RequestPart

前端form加上enctype="multipart/form-data"属性:

:
@RequestMapping(value="/register", method=POST)
public String processRegistration(@RequestPart("profilePicture") byte[] profilePicture, 
                                  @Valid Spitter spitter, Errors errors) {
  ... 
}
接收MULTIPARTFILE

Spring提供了MultipartFile用来对上传的文件封装,便于操作

@RequestMapping(value="/register", method=POST)
public String processRegistration(@RequestPart("profilePicture") MultipartFile profilePicture, 
                                  @Valid Spitter spitter, Errors errors) {
  ... 
}
package org.springframework.web.multipart;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public interface MultipartFile {
  String getName();
  String getOriginalFilename();
  String getContentType();
  boolean isEmpty();
  long getSize();
  byte[] getBytes() throws IOException;
  InputStream getInputStream() throws IOException;
  void transferTo(File dest) throws IOException;
}

transferTo方法可以将文件保存至指定位置

如果使用的Servlet3.0, 可以把上传的文件当做一个PART来解析
@RequestMapping(value="/register", method=POST)
public String processRegistration(
    @RequestPart("profilePicture") Part profilePicture,
    @Valid Spitter spitter,
    Errors errors) {
  ...
}
package javax.servlet.http;
import java.io.*;
import java.util.*;
public interface Part {
  public InputStream getInputStream() throws IOException;
  public String getContentType();
  public String getName();
  public String getSubmittedFileName();
  public long getSize();
  public void write(String fileName) throws IOException;
  public void delete() throws IOException;
  public String getHeader(String name);
  public Collection getHeaders(String name);
  public Collection getHeaderNames();
}

使用write方法将文件保存至指定位置

3. 异常处理

3.1 将异常映射为Http状态码

(1)Spring默认提供了一些状态码映射


Spring MVC进阶知识_第6张图片
image.png

(2) 使用@ResponseStatus注解
首先自定义异常,并使用@ResponseStatus注解

package spittr.web;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")
public class SpittleNotFoundException extends RuntimeException {
}

然后跑出异常即可:


Spring MVC进阶知识_第7张图片
image.png
3.2 异常处理方法

使用@ExceptionHandler注解:

@ExceptionHandler(DuplicateSpittleException.class)
public String handleDuplicateSpittle() {
  return "error/duplicate";
}

这个类可能会抛出DuplicateSpittleException异常:

@RequestMapping(method=RequestMethod.POST)
public String saveSpittle(SpittleForm form, Model model) {
  spittleRepository.save(new Spittle(null, form.getMessage(), new Date(),
          form.getLongitude(), form.getLatitude()));
  return "redirect:/spittles";
}

4. 增强Controller

@ControllerAdvice注解
@ExceptionHandler注解
@InitBinder注解
@ModelAttribute注解

统一异常处理
package spitter.web;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class AppWideExceptionHandler {
  @ExceptionHandler(DuplicateSpittleException.class)
  public String duplicateSpittleHandler() {
    return "error/duplicate";
  }
}

5. redirect

controller返回页面时添加前缀redirect:

  return "redirect:/spitter/" + spitter.getUsername()
Spring MVC进阶知识_第8张图片
image.png
5.1 在redirect时,使用url来传递参数
@RequestMapping(value="/register", method=POST)
public String processRegistration(Spitter spitter, Model model) {
          spitterRepository.save(spitter);
          model.addAttribute("username", spitter.getUsername());
          model.addAttribute("spitterId", spitter.getId());
          return "redirect:/spitter/{username}";
}
5.2 在redirect时,使用flash属性

在Spring中,flash属性被定义为:携带数据到下一次请求

Spring使用Model的子类RedirectAttributes的addFlashAttribute()方法来做这个

@RequestMapping(value="/register", method=POST)
public String processRegistration(
    Spitter spitter, RedirectAttributes model) {
  spitterRepository.save(spitter);
  model.addAttribute("username", spitter.getUsername());
  model.addFlashAttribute("spitter", spitter);
  return "redirect:/spitter/{username}";
}
Spring MVC进阶知识_第9张图片
image.png
@RequestMapping(value="/{username}", method=GET)
public String showSpitterProfile(@PathVariable String username, Model model) {
  if (!model.containsAttribute("spitter")) {
    model.addAttribute(spitterRepository.findByUsername(username));
  }
  return "profile";
}

你可能感兴趣的:(Spring MVC进阶知识)