Spring MVC知识梳理



同上一篇博客,复习梳理SpringMVC知识点,这次的梳理比较快,很多细节没有顾虑到,后期可能会回来补充


1. 整体架构


1.1 在学习了SSM框架后我们来理清三者的应用层面

Spring MVC知识梳理_第1张图片


浏览器发送请求,请求到达SpringMVC处理,然后调用业务层逻辑实现,跟着持久层操作获取数据,最后逆序响应到浏览器。前面我们复习了Mybaits和Spring框架,我们当然不陌生了,现在就来了解下SpringMVC到底有什么作用



1.2 MVC

MVC模型中,M是把浏览器传的参数封装成的pojo类型,V则代表视图,C就是控制器也是重点。SpringMVC是以组件的形式来形成整体的,下面也是画图来解释


Spring MVC知识梳理_第2张图片
网图,侵删


  • 核心控制器被Tomcat初始化并主动加载applicationContext配置文件
  • 用户发送请求
  • 请求到达核心控制器
  • 核心控制器交由映射器处理映射地址
  • 核心控制器找到适配器来适配处理器(适配器模式)
  • 将请求过来的数据进行转换
  • 将转好的数据给处理器处理并沿路返回
  • 最后通过视图解析器解析
  • 响应对应的页面

从上面可以看出 DispatcherServlet 是核心指挥中心,MVC框架围绕其来设计的,处理所有的http请求和响应


DispatcherServlet 收到请求后根据HandlerMappering来选择并且调用映射的控制器


控制器接收到请求后基于GET、POST调用适当的Servce方法后将数据返回到DispatcherServlet中


上面所说的HandlerMapping、Controller是WebApplicationContext的一部分,其是ApplicationContext的扩展,也是BeanFactory的扩展


启动Tomcat,初始化web.xml中的 DispatcherServlet ,而DispatcherServlet 框架则尝试加载applicationContext.xml配置文件内容







2. 映射关系

MVC作用在表现层用来处理请求,所以地址映射也在这里,即在Controller中,请求是在方法上处理的,不是类上(这也是单例的原因,类上使用映射即为分模块作用),方法的返回值默认为返回的网页地址(现在前后端分离使用得比较少了,下面讲解都是用前后端分离模式),其映射关系使用注解的过程为:


@Controller
@RequestMapping("/user")
public class HelloController {

    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String sayHello(){
        System.out.println("Hello World");
        return "success";
    }
}






3. 参数绑定

这里是重点,因为请求一般都带数据的,然后在这里绑定成Model,方便我们使用,不用再像JavaWeb程序中request.getParameter()了,支持基本类型、String类型,bean类型以及集合类型


这里一个小插曲,如果要获取request、response,则在方法参数上自己添加即可


3.0 这里先给出需要用到的Bean

public class User {

    private int id;
    private String name;
    private String email;
    private InnerBean innerBean;
    private List innerBeanList;
    private String[] array;

 	// 省略各种getter / setter
}
public class InnerBean {

    private String inner;

    public void setInner(String inner) {
        this.inner = inner;
    }
}

3.1 简单参数绑定

MVC框架会在方法参数中绑定请求中名字相同的变量(使用了反射),简单参数为基本类型和String,参数名若不同则使用@RequestParam注解绑定

id: name: email:
// 表单中name和形参名字相同 // 简单参数 @RequestMapping(value = "/param1") public String getParameter1(String id, String name, String email) { System.out.println(id + name + email) ; return "success"; }

3.2 Bean封装

bean类型封装是用过里面的setter实现的,而且还有bean中有bean的情况

id: name: email: inner:
// 封装Bean对象,依靠setter方法 @RequestMapping(value = "/param2") public String getParameter2(User user) { System.out.println(user) ; return "success"; }

3.3 集合封装

id: name: email: inner: inner: inner: inner:
// 封装集合 @RequestMapping(value = "/param3") public String getParameter3(User user) { System.out.println(user) ; return "success"; }






4. 类型转换器

请求传过来的数据都是字符串,那么我们使用的时候为什么可以获取其他类型呢?这里是使用了框架内部的默认转换器所以才可以取得其他类型数据,但如果默认转换器识别不了,那么我们就要自己配置类型转换器来实现功能


这里有个场景:前端传2020/3/2过来让Date类型接收是没问题的,但是如果前端传了2020-3-2呢?这样就会报错,因为2020-3-2框架没有这个转换器来转成Date类型,那么就需要我们手动来设置


@Controller
@RequestMapping(value = "/converter")
public class ConverterController {

    @RequestMapping(value = "/converter")
    public String converterMethod(Date date){
        System.out.println(date);
        return "success";
    }
}

4.1 创建转换器类

这个类实现了Converter接口,这个泛型要自己添加,返回类型为转换好的类型

public class StringToDateConverter implements Converter {

    /**
     * 需要自己手动添加泛型,s指传进来的字符串
     */
    public Date convert(String s) {
        s = s.replace('/','-');
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-DD");
        try {
            return sdf.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

4.2 将自定义转换器注册在转换器服务工厂中,并给容器管理



    
    	
        
            
        
    


4.3 注册组件

因为MVC是基于组件的,所以使用了组件就要在配置文件中注册









5. 文件上传

要求:

1、表单要是enctype="multipart/form-data"

2、方法要是POST

3、输入框要是


当上传表单为多个文件时,根据hppt请求体来分割很复杂,所以要借助第三方jar,也就是传统的上传方法,该方法依赖 commons-fileupload(当然下面的MVC的简化文件上传也要该依赖),传统的文件上传笔者已经写过一篇博文了,请点击这里


至于MVC的上传呢,更加简便。MVC提供了MultipartFiled对象,需要表单的name与之对应

文件上传

选择文件: 选择文件:
@RestController @RequestMapping(value = "/upload") public class FileUploadController { @RequestMapping(value = "/upload") public String fileUploadMethod(HttpServletRequest httpServletRequest, MultipartFile[] uploads) throws IOException { // 创建目录 String path = httpServletRequest.getSession().getServletContext().getRealPath("/uploads/"); File file = new File(path); if(!file.exists()){ file.mkdirs(); } for(MultipartFile value : uploads){ // 原名 String originalFilename = value.getOriginalFilename(); // 生成随机名 String fileName = UUID.randomUUID().toString().replace("-","") + "_" + originalFilename; // 和传统文件上传不同,参数为File,差别看博客 value.transferTo(new File(path,fileName)); } // 笔者这里返回了地址,一般返回成功消息的 return path; } }

MVC是基于组件的,所以文件解析器也是一个组件需要配置




    
    







6. 异常处理

Spring MVC知识梳理_第3张图片


正常操作是底层发生异常会一直向上抛,直到发给浏览器用户看到,我们要避免这种事情发生,就需要异常处理,所以我们要把流程改成下面这样


Spring MVC知识梳理_第4张图片


6.1 编写自定义异常类(做提示信息)

public class MyException extends Exception {

    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public MyException(String msg) {
        this.msg = msg;
    }
}


6.2 编写全局异常处理器(注解版)

// 获取所有异常
@RestControllerAdvice()
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    public String handleException(Exception e){

        // 如果是自定义异常,则发送自己的消息
        if(e instanceof MyException){
            return ResponseHelper.error(((MyException) e).getMsg(),new User());
        }

        // 否则发送系统错误
        return ResponseHelper.error("系统错误");
    }
}






7. 拦截器

类似于Filter,但拦截器是对处理器Controller进行预处理和后处理,不同于Filter拦截Servlet。拦截器是MVC内部的,使用MVC框架才有拦截器,而过滤器是javaWeb内部的。范围不同,Filter中配置 /*会过滤所有请求,拦截器应用场景有:权限检查和日志处理


7.1 实现HandlerInterceptor

这个接口要自己手动输入重写,因为1.8之后接口变了,笔者在这里配置权限检查


public class MyInterceptor implements HandlerInterceptor {

    /**
     * @return true表示放行,执行下一个拦截器,false表示拦截
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        Object user = request.getSession().getAttribute("user");
        if(user == null){
            // 没登录,重定向
            response.sendRedirect("/admin/login.html");
        }
        // 否则放行
        return  true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}


7.2 applicationContext配置拦截器

万物皆组件




    
        
        
    
    
    
    
        
        
    








8. 注解总览

@Controller
@RequestMapping(value = "/hello",method = RequestMethod.GET)
@RequestParam(value = "name") // 用于匹配名字不一致
@PathVariable(value = "sid")  // 绑定url中的占位符,主要用于Restful风格,下面有这里

@ResponseBody // 主要用于响应json数据,即Controller方法的返回值通过适当转换器后,写入Response不走视图解析器,笔者用fastjson将bean转换成json即String类型返给前端,即前后端分离

@RequestBody  // 若异步请求,则发送给后端的是json数据无法绑定参数,用了这个注解,将获取请求体中全部参数,以key=value的形式,get方法不在请求体中,无法使用,当以键值对出现时,则是换成普通请求的数据格式,使用setter将绑定参数

@@RestController // @Controller和@ResponseBody的结合,用于前后分离,不走视图解析器,可放于类上,则类中的全部方法适用,而@RequestBody则不行

@PathVariable

@RequestMapping("/anno2/{sid}")
public String annoMethod2(@PathVariable(value = "sid") int id) {
    System.out.println(id);
    return "success";
}






9. 补充


@RestController中文乱码

其默认使用tomcat的编码,而且直接返回给前端所以会乱码


方法一:映射注解上加属性
@RequestMapping(value = "/user", produces = "application/json;charset=utf-8")


方法二:全局配置编码问题



    
        
            
        
    



DispatcherServlet在配置映射关系中用/,则会拦截所有请求,包括静态资源而导致无法访问,所以要在applicationContext中配置不拦截




MVC 三大组件:适配器,映射器,解析器


在Spring的基础上需要的额外jar包:spring-web、spring-mvc


约束






pom.xml



    4.0.0

    com.howl
    SpringPractice
    1.0-SNAPSHOT
    war

    
        
            org.springframework
            spring-context
            5.0.2.RELEASE
        
        
            org.springframework
            spring-test
            5.0.2.RELEASE
        
        
            junit
            junit
            4.12
            test
        
        
            org.junit.jupiter
            junit-jupiter
            RELEASE
            test
        
        
            org.aspectj
            aspectjweaver
            1.8.7
        
        
            org.springframework
            spring-tx
            5.0.2.RELEASE
        
        
            org.springframework
            spring-jdbc
            5.0.2.RELEASE
        
        
            mysql
            mysql-connector-java
            5.1.6
        

        
            org.mybatis
            mybatis
            3.5.1
        
        
            org.mybatis
            mybatis-spring
            2.0.1
        
        
        
            commons-fileupload
            commons-fileupload
            1.4
        
        
        
            com.alibaba
            fastjson
            1.2.62
        
        
        
        
            javax.servlet
            servlet-api
            2.5
            provided
        

    



你可能感兴趣的:(Spring MVC知识梳理)