Spring 实战-第七章-Spring MVC的高级技术

1.处理multipart形式的数据

对于文件,Spring可以支持multipart形式的数据,但是DispatcherServlet没有实现任何解析multipart请求数据的功能,需要配置一个解析器用来解析multipart。

DispatcherServlet将该任务委托给了Spring中的MultipartResolver策略接口的实现,Spring内置了两个实现可以选择:

  • CommonMultipartResolver:使用Jakarta Commons FileUpload解析multipart请求;
  • StandardServletMultipartResolver:依赖于Servlet3.0对multipart请求的支持(始于Spring3.1)

声明MultipartResolver的Bean

    @Bean
    public MultipartResolver multipartResolver() throws IOException {
        return new StandardServletMultipartResolver();
    }

 

使用的时候,必须在web.xml或Servlet初始化类中,将multipart的具体细节(文件路径、大小等)作为DispatcherServlet配置的一部分,否则无法正常使用。

如果采用Servlet初始化类的方式配置DispatcherServlet的话,这个类已经实现了WebApplicationInitializer,那么可以在Servlet registration上调用setMultipartConfig()方法,传入一个MultipartConfigElement。

DispatcherServlet ds=new DispatcherServlet();
Dynamic registration=context.addServlet("appServlet",ds);
registration.addMapping("/");
registration.asetMultipartConfig(
    new MultipartCofigElement("/tmp/spittr/upolads"));

如果配置的Servlet初始化类继承了AbstractAnnotationConfigDispatcherServletInitializer或AbstractDispatcherServletInitializer的话,可以重载customizeRegistration()方法来配置multipart的具体细节。

//设置multipart上传配置,路径,文件不超过2MB,请求不超过4MB
    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration){
        registration.setMultipartConfig(
                new MultipartConfigElement("C:/test",2097152,4194304,0));
    }

页面增加input标签

<input type="file" name="profilePicture" accept="image/jpeg,image/png,image/gif"/>

处理multipart请求,最常用的是在控制器方法参数上添加@RequestPart注解,接收multipart数据可以使用byte[]、MultipartFile、Part等形式,MultipartFile与Part类似,都包含保存到文件系统的方法。

    @RequestMapping(value="/register",method = POST)
    public String processRegistration(
            @RequestPart("profilePicture") MultipartFile profilePicture,
            @Valid Spitter spitter,
            Errors errors, RedirectAttributes model) throws IOException{
        if(errors.hasErrors()){
            return "registerForm";
        }
        spitterRepository.save(spitter);
        //如果有上传文件,则保存到指定位置
        if(!profilePicture.isEmpty()) {
            profilePicture.transferTo(new File(profilePicture.getOriginalFilename()));
        }
        model.addFlashAttribute("spitter",spitter);
        return "redirect:/spitter/"+ spitterRepository.findByUsername("").getUsername();
    }

 

7.3处理异常

默认情况下,Spring会将吱声的一些异常自动转为为合适的状态,此外,我们可以对应用抛出的异常进行个性化的处理。

  • 将应用异常转为HTTP状态

通过@ResponseStatus注解,可以将异常类转换为特定的HTTP状态,并且增加相关信息

@ResponseStatus(value= HttpStatus.NOT_FOUND,reason = "将异常映射为特定的状态码")
public class ErrorOneException extends Exception {

}

 

当代码抛出被包装的异常后,网页会使用异常指定的状态码,并且显示相关信息

//将异常映射为特定的状态码
    @RequestMapping(value="/errorone",method = GET)
    public  String errorone(Model model) throws ErrorOneException{
       throw new ErrorOneException();
    }

  

  • 编写处理异常的方法

在某些情况下,主动抛出异常,不仅会增加无关的逻辑,并且通过异常机制处理可能不能满足需求,需要对于特定异常进行更复杂的操作,比如跳转到其他页面,

这时候在@ExceptionHandler注解,可以处理指定类型的异常

    //编写处理异常的方法
    @RequestMapping(value="/errortwo",method = GET)
    public  String errortwo(Model model){
       int a=1/0;//会抛出ArithmeticException
       return "test";
    }

    //编写处理异常的方法
    @ExceptionHandler(ArithmeticException.class)
    public String handleErrorTwo(){
        return "error";//使用error视图进行渲染
    }

 

7.4 为控制器添加通知

Spring3.2引入的控制器通知(controller advice),是任意带有@ControllerAdvice注解的类,这样控制器类的特定切面能够运用到整个应用程序的所有控制器中。

这个类包含一个或多个如下类型的方法:

  • @ExceptionHandler注解标注的方法;
  • @InitBinder注解标注的方法;
  • @ModelAttribute注解标注的方法。

在带有@ControllerAdvice注解的类中,以上所述的这些方法会运用到整个应用程序所有控制器中带有@RequestMapping注解的方法上。

@ControllerAdvice注解本身已经使用了@Component,因此@ControllerAdvice注解锁标注的类将会自动被主键扫描获取到。

比如7.3中的异常处理,就可以将异常处理统一到一处

@ControllerAdvice
public class AppWideExceptionHandler {

    @ExceptionHandler(ErrorThreeException.class)
    public String errorThreeExceptionHandler(){
        return "error";
    }
}

 

 

7.5跨重定向请求传递数据

当使用“redirect:”前缀进行重定向的时候,由于模型数据已经随着上一个请求的结束而消亡,无法传递到下一个请求中,Spring提供了flash(闪存)属性,用于存储这类模型数据。

相比Session存储,flash的好处在于,其生命周期只延续到下一个请求,请求结束后就会消失。

 

使用flash存储模型数据

    //使用flash存储模型数据
    @RequestMapping(value="/flash",method = POST)
    public String processFlash(Spitter spitter,
           RedirectAttributes model) {
        model.addFlashAttribute("spitter",spitter);
        return "redirect:/spitter/test";
    }

 

 读取flash中的模型数据,当model中没有spitter属性时,使用查询数据库,否则就使用属性中的,当返回到页面请求结束,flash中的数据就没有了

    //读取flash中的模型数据
    @RequestMapping(value = "/{username}",method = GET)
    public String showSpitterProfile(
            @PathVariable String username,Model model){
        if(!model.containsAttribute("spitter")) {
            Spitter spitter = spitterRepository.findByUsername(username);
            model.addAttribute(spitter);
        }
        return "profile";
    }

 

sourceCode:https://github.com/ljw8947/SpringInAction/tree/master/Capter7/Spittr

 

posted on 2017-11-29 18:07  Lv Jianwei  阅读(484)  评论(0编辑  收藏  举报