SpringMvc概述

137 阅读15分钟
Springmvc表述层(Controleer层)框架

一:SpringMvc简介和快速入门

1.1:介绍:

1.SpringMvc是一个Web框架,作用于表述层(Controller层); (也叫SpringWebMvc,是基于Spring Framework)
  它内部封装的是:Servlet;是基于Servlet的框架
    
2. 之前我们进行操作是:: 1.接收前端参数
                        2.调用业务逻辑(Service层)
                        3.响应前端数据
   SpringMvc重要作用!!!!:
             简化接收前端参数;
             简化响应给前端数据
    
 3.我们需要学习/重点掌握:如何SpringMvc如何  简化接收前端参数:普通参数、JSON参数、文件、cookic、session!!!!!
                 如何简化返回给前端的数据:!!!!!!!!!
    
              

1.2:SpringMvc内部流程和核心组件

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
执行过程:
  SpringMvc是基于Servlet的框架:内部封装了dServlet
  之后前端所有的请求全都会交给 dServlet去处理,然后,Servlet通过请求路径去到HandlerMapping中去找有没有对应handler方法;
  然后:
1)核心组件:
 SpringMvc提供了类(组件),我们只需要进行ioc配置,使其加入ioc容器即可!!!;
 
         1.DispatcherServlet[CEO]:SpringMvc提供,他是整个流程处理的核心,所有的(请求)都要经过它的处理和分发!!

         2.HandlerMapper[秘书]:它内部缓存了handler(controller的方法) 和 handler的访问路径数据,
                              !!被DispatcherServlet调用,用于:!!!!查找路径对应的handler;
         3.HandlerAdapter[经理]:!!处理请求参数和处理响应数据,
                                每次DS都是通过它间接调用handler,他是DS和handler之间的适配器;

         4.Handler:处理器,是Controller层的方法的简称;(我们把Controller层的每个方法称为1个Handler)
          它需要我们自己定义,!!用来接收参数,向后调用业务层(Service层),最终完成响应结果!!!;
         5.ViewResolver:视图解析器
    
(2)操作方法/流程:	~!!!!!!!!!!!!  !!!!!!!!!!
                    我们只需要将DispatcherServlet配置到生效
                    将.HandlerMapper 和  HandlerAdapter放到ioc容器
                    最后我们自己再定义handler即可
    

     
(4.)SpringMVc内部调用流程:

1.3 SpringMvc快速入门:

springmvc-base-quick-01!!!

需求:
  定义1个hanlder,只要外部访问hanler方法对应的地址,我们响应给前端 ”hello springmvc“;
分析:
  1. DispatcherServlet,设置处理所有请求!,使它生效!
  2. HandlerMapping,HandlerAdapter,Handler需要加入到IoC容器,供DS调用!
  3. Handler自己声明(Controller)需要配置到HandlerMapping中供DS查找!  
过程:!!!!!!!!!
  1.创建Controller类:并添加到ioc容器
  2.在Controller类中定义handler方法,
     使用@RequestMapping 将handler添加到HandlerMapping + 指定外部访问路径
  3.创建配置类:将 HandlerMapper、controller、HandlerAdapter 加入ioc容器
  4.创建初始化类:完成web加载、ioc容器创建、Servlet拦截;路径
  
  

二:SpringMvc接收数据

springmvc-base-input-02

重点学习:
  SpringMvc如何在handler方法中简化参数的接收
访问过程:

  handler最终是被客户端(浏览器)访问的;
  -->客户端通过http协议(get、post、put、delete)先访问到dServlet-->最后再访问到handler;

2.1:如何设置访问路径:路径设置注解@RequestMapping:

访问路径:客户端通过访问路径访问到资源(eg:dServlet);

@Controller //将Controller类加到ioc容器;

@RequestMapping("/user")
//@RequestMapping:加到类上:将方法公共的地址:/user,加到类上,下面的方法只写方法特有的地址!!!!
public class UserController {

    /*
    @RequestMapping:
      1.作用:注册地址:
       将handler方法注册到RequestMapping中,且在内部可以设置访问路径
      2.@RequestMapping中的访问地址:不一定以 "/"开头。 eg:/user/login、 user/login
        原来web.xml文件中必须以'/'开头
      3. (1)设置精准地址:({"地址1","地址2"...})
         (2)设置模糊地址:"*":任意一层字符串; "**":任意层任意字符串;
         eg: 如果我们在@RequestMapping:内写的是:/user/*:
              那我们在外部:使用:/user/a 、/user/aaa 都可以访问到;
      4.@RequestMapping路径设置注解: 可以加到方法上,也可以加到类上;
          区别:
             加到方法上的:具体的handler地址
             加到类上的:是提取的类下方法的通用/公共的部分地址; eg:/user
           方法上是必须加,类上可以不加;
     5.请求方式指定:

     访问过程:
  handler最终是被客户端(浏览器)访问的;
  -->客户端通过http协议(get、post、put、delete)先访问到dServlet-->最后再访问到handler;


     如何指定请求方式:(指定之后:就只能固定的请求方式可以访问资源dServlet!!!!)
       默认情况:只要客户端发送请求的地址正确:任何请求方式都可以访问dServlet:@RequestMapping("login")
       指定请求方式:
          方法1:在路径设置注解中添加属性:method=""; eg:@RequestMapping("login",methods={RequestMethod.GET,RequestMethod.POST)
          
注解进阶:!方法2:在相应的方法上:加上对应的注解:eg:@GetMapping、@PostMapping、@PutMapping、@DeleteMapping
             但是不能加到类上
       
       如果不符合请求方式:会出现405异常;
     */

    eg:
    @RequestMapping("login") 
    public String login(){

        return null;
    }
    @GetMapping("/o1")  //使用注解设置提交方式:为Get:之后客户端在请求资源时就只能以get方式请求
    public String o1(){
        return null;
    }
    @PutMapping("/o2") //使用注解设置提交方式:为put:之后客户端在请求资源时就只能以put方式请求
    public String o2(){
        return null;
    }

}

2.2如何接收参数(重点!!!)

接收 来自前端(浏览器)传过来的 地址上的参数(参数有多种)!!!!!
    
 我们重点学习:如何接收前端发送的各种类型的参数;!!!!!!

2.2.1.param和json

1)param和JSON的对比:

1.param参数形式:
   key=value & key=valeu
2.json参数形式:
   {key:value,key:value}
3.param 和 JSON 两种参数形式的比较:
     (1)参数编码:
         param:Ascall编码; JSON:UTF-8;
      (2)参数顺序:
          param:参数没有顺序;
          JSON:参数有顺序; 
      (3)数据类型:
           param:只支持字符串类型; eg:在前端传来参数:name=张三&age=18 最终都会转换成字符串类型;
           json:可以装多种;
      (4)嵌套性:
           param:无嵌套:只有1层
           json:可以无限嵌套,只要符号json的格式;
       (5)可读性:
           简单的参数:param读起来较为简单
           复杂的参数:json读起来清晰;
           
      注意:一般使用JSON,且JSON格式传递要求请求方式必须是POST;!!!!!!!!!

2.2.2:param方式如何接收参数:

(2)如何接收前端发送的Json和param类型的参数;



    接收方式有三种:
  1.直接接收:
  
  2.注解指定
  
  3.特殊值
  
  4.使用实体类对象接收;
      


    /*
    1.直接接收:(直接接值)
      eg:!!!当前端发送:/param/data?name=root&age=18
      如何接收:handler方法的形参列表 填写对应名称的参数即可!  形参参数名= 前端访问的参数名 即可;
      1.名称相同; 2.可以不传递,不会报错;
     */
    //handler方法:
    @RequestMapping("/data")  //将handler注册到handlerMapper + 外部访问handler的地址;
    @ResponseBody
    public  String data(String name,int age){
        System.out.println("name = " + name + ", age = " + age);
        return "name =" +name+"age ="+age;

    }

    /*
    2.注解指定:(注解接值)
    @RequestParam:放在形参列表,用来指定:请求参数名 或者 是否必须传递 或者非必须传递情况下设置默认值;
    用法:@RequestParam(value="指定请求参数名":如果新参名称和请求参数名一样可以省略;如果指定了value,原来的参数就会失效,只有传入指定的参数才会生效:
                       required=false:前端是否必须传递此参数,默认是必须传,否则报400异常
                        defaultValue="1":当为false时非必须传递时,可以设置默认值;)

        eg: !!当前端发送:/param/data1?account=root&page=1;
            要求:account必须传递,page可以不传递,如果不传递默认值就是1
     */
    @RequestMapping("/data1")
    @ResponseBody
    public String data1(@RequestParam(value = "account") String name, //value:指定参数名,请求参数必须传account!!!!
                        @RequestParam(required = false,defaultValue = "1") int page){
        //required=false(代表不是必须传递)和defaultValue(代表默认值)一定是一块出现的

        System.out.println("name = " + name + ", page = " + page);
        return "name = " + name + ", page = " + page;
    }

    /*
    3.一名多值:(集合接值)
        如何接收参数:直接在方法形参处:使用“集合”进行接收;
      eg:!!当前端传来: /param/data2/hobby=唱& hobby=跳&hobby=rap
         注意:在形参处:必须加上@RequestParam!!!!!!!!!
     */
    @RequestMapping("/data2")
    @ResponseBody
    public String data2(@RequestParam List<String> hbs){
        System.out.println("hbs = " + hbs);
        return "ok";
    }

    /*
    4.!!!!!!!使用实体对象接值:
       eg:前端传:/param/data3?name=二狗子&age=18
     如何接收参数:准备一个有对应的属性、get/set方法的实体类即可; 然后在handler方法形参中传入实体类对象即可;
     注意:实体类的属性名一定要等于前端传入的参数名!!!
     */

    @RequestMapping("/data3")
    @ResponseBody
    public  String data3(User user){
        System.out.println("user = " + user);
        return user.toString();
    }


}

2.2.3:路径参数接收:


  eg:原来:/user/login?account=root&password=123456
      路径传参:/user/login/root/123456:这个root和"123456"本身已经是参数了;

 实现步骤:
      1.设置动态路径:即使用@RequeatMapping({key1},{key2});
      2.接收动态路径参数 :在方法形参中必须使用@PathVariable注解指定参数
         因为(String username,String password)是用来接收Param格式的参数的!!!!!
         而@PathVariable才是用来接收路径参数的!!!!!!!!;

 路径参数演示:
  eg:  /path/root/密码


 */
@Controller
@RequestMapping("path")
@ResponseBody
public class PathController {

    //handler方法:

    //1.设置动态路径:{key}
    @RequestMapping("{account},{password}")
    public String login(@PathVariable(value = "account") String username, @PathVariable String password){
    //2.路径参数的接收:必须使用:@PathVariable注解在形参来指定接收参数
        System.out.println("username = " + username + ", password = " + password);
        return "username = " + username + ", password = " + password;

        //访问时:/path/root/123
    }

2.2.4;json参数接收:

学习目标:
  :在前端发送json格式的请求:我们如何在后端进行接收;

Json格式的数据:前端必须使用 “ Post ”的方式进行请求;
Json是通过体进行发送的
    
 1. Json:是在JS中的一种“ 对象 ”表达方式; 我们使用对应的 “ 实体类 ”进行接收就行了;
 2.在handler方法形参处:使用@Request注解指定参数(因为json是放到请求体中的!!!)
 3.在配置类最上方:加@EnableWebMvc //给handlerAdapter配置json转换器
     
   注意:@EnableWebMvc: 添加HandlerMapping、HandlerAdapter、以及json转换器
         所以加上这个注解之后:我们就不需要在配置类中:写HandlerMapping、HandlerAdapter了!!!!!!!!!
eg:
  /handler
    @PostMapping("data")
    public String data(@RequestBody Person person){
        //因为是Json格式的参数:使用@RequestBody注解 指定参数
        System.out.println("person = " + person);
        return person.toString();

        //最终:我们:在postman:
        //会415异常:因为java原生的api只支持路径参数和param参数;
        //因为json是前端的格式

        /*、
        解决方法:
          1.导入json的依赖
          2.handlerAdapter配置json转换器
             在配置类上加上:@EnableWebMvc (//给handlerAdapter配置json转换器)
         */

    }

2.3如何接收Cookie数据


@Controller
@RequestMapping("cookie")
@ResponseBody

public class CookieController {

    //handler:

    //(2)前端携带cookie来访问,后端接收Cookie;
      //即在handler方法中:使用@CookieValue注解指定参数
    @RequestMapping("data")
    public String data(@CookieValue(value = "cookieName") String value){
        System.out.println("value = " + value);

        return "value = " + value;

    }

    //(1)存Cookie@:即后端得先创造1个cookie,交给/存到前端; 之后前端才可以拿着cookie访问资源
    @GetMapping("save")
    public String save(HttpServletResponse response){   //response对象直接在形参处声明即可,之后下方就可以直接使用了!!
                      /
        Cookie cookie=new Cookie("cookieName","root"); //a:创建cookie对象
        response.addCookie(cookie);  //b:将cookie放入响应对象中,携带到客户端,下次再请求时就会带到后端
                                       //后端交给前端,所以是:放入响应对象中来传给前端
        return "ok";
    }

}

  

2.4接收请求头数据:

使用@RequestHeader("要接受的名称")指定handler形参!!


@Controller
@ResponseBody
@RequestMapping("header")
public class HeaderController {

    //handler
    @GetMapping("data")
    public String data(@RequestHeader("Host") String host){
   //接收请求头:在形参处:使用@RequestHeader("Host")注解指定参数:代表接收Host头,然后赋值给String host
        System.out.println("host = " + host);
        return  host;
    }

2.5原生对象如何获取:


@Controller
public class ApiController {

    //第二种:声明全局变量:全局注入

    @Autowired //ioc容器获取对应类型的实体对象,并自动装配;
    //在程序启动时:ServletContext会自动装入ico容器
    private ServletContext servletContext;



    //第一种:
    //先直接在形参处声明
    //然后在下方:直接使用原生对象即可
    public void data(HttpServletResponse response,
                     HttpServletRequest request,
                     Session session){

        //下方直接使相应的变量即可 eg:
        RequestDispatcher s = request.getRequestDispatcher("s");
        
    }
}

2.6如何获取共享域对象以及共享域对象的操作:

共享域:
    
    
常用的三个范围(请求域,会话域,共享域):
    request:一次请求以及转发之内
    session:一次会话之内:一个浏览器的多次请求
    servletContext:整个项目;
    
共享域操作:
    存:setAttribuet(key,"object value")
    取:get..
    更新:set.. :两次set相同的key会进行更新
    删除:remover...;
    
 获取共享域:
    
     //获取共享域:
      //(1)
      //方法1:原生api:直接在形参处声明即可
     public void data(HttpServletRequest request,
                      HttpServletResponse response, Session session){

     }
     //方法2:声明全局变量
      //声明为全局变量:就拿到了
    @Autowired
    private ServletContext servletContext;

     //(2)
     //SpringMvc针对request提供了几种方式; (了解)

三SpringMvc如何简化数据响应:

响应数据:
   即后端接收前端发送的数据之后,要将返回结果返回给前端:
返回结果一般有两种:
   1.页面跳转(返回视图页面)
   2.返回数据(一般是json)
   
   
public Object handler(简化请求参数){
   调用业务方法
   返回结果(1.页面跳转,2.返回数据(json));
   return “ 简化响应前端数据 ”
}

3.1混合开发下handler如何快速返回模板页面:

3.2前后端分离下后端如何返回json数据(重点!!!!)

@ResponseBody:把返回的对应Json数据直接返回给客户端,而不去走视图页面;!!!
   

@Controller //加到ioc容器
@RequestMapping("json")
@ResponseBody //返回json的注解:可以添加到类/方法上


public class JsonController {
    //handler

@ResponseBody //代表:把数据直接返回字符串,不找视图页面!!!
@GetMapping("data")

    //1.接收json:直接将方法的返回值设为json对应的实体类!!!!!!!!!
    public User data(){ //后端接收前端发送的json:
        User user=new User();
        user.setName("egz");
        user.setAge(18);

        return user; //user会在handlerAdapter种转为json字符串
    }

    //2.
    @ResponseBody
    @GetMapping("data1")
    public List<User>data1(){

        User user=new User();
        user.setName("egz");
        user.setAge(18);
        List<User> users=new ArrayList<>();
        users.add(user);
        return users;

    }
}

注意:1.要返回json:必须加上@ResponseBody注解:代表 数据直接放入响应体返回!不会走视图解析器;!!!!!!!!!
       快速查找视图和 转发重定向就都不生效了;
      2.@ResponseBody注解可以加到方法上,也可以加到类上;
      3.如果这个类中:所有的方法都是返回json的,我们可以在类上添加:@RestController注解:=@Controller+@ResponseBody

3.3返回静态资源处理:

静态资源:html页面,图片...
    
 默认情况下:无法访问静态资源,我们需要开启静态资源查找:
     之后dispatcherServlet会去handlerMapping中去找有没有对应的handler,如果没有就访问静态资源;

  在配置类中:
        //开启静态资源处理 <mvc:default-servlet-handler/>
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }

四:RESTFul风格设计和实战

4.1 RESTFul风格概述

背景:
   客户端和java程序:通过Http协议进行交互
   Http协议: 
        1.url【地址】
        2.请求方式:get、post、put、delete
        3.传递参数:param】json、path;
    但是我们面临:每次该如何设计 url、请求方式、传递参数;
  因此我们使用RESTFul:

(1)RESTFul:
  RESTFul:是Http协议的标准使用方案和风格;!!!!!!!
    它会教我们如何设计路径url,如何选择请求方式、如何设计参数传递(param、json、路径参数);!!!!!
    
 (2)使用了RESTFul。就是RESTFul风格;
 

4.2:RESTFul:风格特点:

1.客户端和服务端之间的交互是无状态的,从客户端到服务端的每个请求都必须包含所必须的信息
2.交互的数据使用json!!!!!
    
  RESTFul特点: 
1每一个URI/url为是名词!!!;
2.要求你使用对应的“ 请求方式 ”来指定对应的动作:
     eg:获取/查询操作:使用get
         删除操作:使用delete请求方式
         增加/保存操作:post
         更新操作:put
   注意:但是不要在url中加上crud动作,url中只包含名词!!!
        eg: /CRUD/saveEmp -->:/../emp +使用get请求方式!!!!
            
   总结:
         RESTFul:根据具体的动作选择具体的请求方式:增删改查操作:选择对应的请求方式;
                  路径url只包含n即可;
         

4.3RESTFul 实战分析:!!!!!

分析:
    学习如何选择请求方式、设计请求参数、请求路径:!!!!
    
(1)
没有请求体: 
   获取:get
   删除:delete
  这两种可以使用: /url +路径参数
                 /url ? +param
                 
              
    
     注意:使用get/delete 时
    
           1.当参数是id标识时:,选择使用路径传递参数!!!
           eg:根据id删除/查询数据:--->: 	/模块/id
            
           2.当参数不是id,是范围参数时:,选择使用param传递参数!!!
            eg: param key=value;
   
(2)  
有请求体:
   保存:post
   修改:put
这两种可以使用:
       /url + 路径参数
       /url ? + param
       请求体传参(json)!!!一般使用json!!!
       
   注意:当使用post时:我们一般使用请求体json!!!!!
    
 
    总结:!!!!!!!!!!!!!
       第一步:选择对应的动作(请求方式):crud
       第二步:看参数是什么:
       第三步:路径:/模块;


结合案例!!!!!!!!!!;

五:SpringMvc其它扩展

5.1:全局异常处理机制:

5.1.1异常处理的两种机制:

1.编程式异常处理:
   在代码中显示的编写处理异常的逻辑; eg:使用try-catch来捕获异常,然后再catch中编写特定的处理代码,或者再finally中执行一些清理操作;--》:即开发人员需要显示的进行异常处理,可读性较差;
   
2.声明式事务处理:将异常处理的逻辑从具体业务中提取出来,通过配置等方式进行统一管理;
-->:在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws@ExceptionHandler),就可以处理特定类型的异常。

5.1.2:声明式事务处理:

步骤:
   1.声明一个全局异常处理类(全局异常处理器);:使用@RestControllerAdvice注解(底层是aop)
   
   2.在里面写若干个异常处理方法handler:
     在handler上通过@ExceptionHadler注解来指定对应的异常类型;
     之后发生响应的异常就会调用对应的handler方法;

  注意:@RestControllerAdvice注解:代表handler方法处理完之间返回字符串;