SSM框架,SpringMVC框架的学习(下)

SpringMVC响应数据

handler方法分析

一个controller层的方法是控制层的一个处理器,称之为handler

handler方法需要使用@RequestMapping或@GetMapping等一系列注解,声明路径,以在HandlerMapping中注册,供DS查找

handler方法的作用

  1. 接收请求参数(param、json、pathvariable、共享域等)
  2. 调用业务逻辑
  3. 响应前端数据(页面、json、转发和重定向等)

页面跳转控制

快速返回模板视图

jsp视图解析器的配置

依赖导入

<!-- jsp需要依赖! jstl-->
<dependency>
    <groupId>jakarta.servlet.jsp.jstl</groupId>
    <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
    <version>3.0.0</version>
</dependency>

准备jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--    ${data}用来获取共享域中名为data的共享数据--%>
<font color="red">${data}</font>
</body>
</html>

配置类:

/**
 * mvc组件的配置类
*/
@Configuration
@ComponentScan("com.ergou")
@EnableWebMvc
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
//registry可以快速添加前后缀
registry.jsp("/WEB-INF/views/",".jsp");
    }
}

handler方法:

@Controller
@RequestMapping("jsp")
public class JspController {
/**
     *快速查找视图
* 1.方法的返回值是字符串类型
* 2.不能添加@ResponseBody注解
* 3.返回值为对应的中间视图名称
* @return
     */
@GetMapping("index")
    public String index(HttpServletRequest request){
        request.setAttribute("data","hello,jsp");
        return "index";
    }
}

请求转发和响应重定向实现

  • 请求转发的步骤
    • handler方法的返回值类型为String类型
    • 不添加@ResponseBody
    • 返回的字符串写要转发的地址,并在地址前加上 forward:

例:

//请求转发
    @GetMapping("forward")
    public String forward(){
        System.out.println("请求转发");
        return "forward:/jsp/index";
    }
  • 响应重定向的步骤
    • handler方法的返回值类型为String类型
    • 不添加@ResponseBody
    • 返回的字符串写要响应重定向的地址,并在地址前加上redirect:

例:

//响应重定向
@GetMapping("redirect")
    public String redirect(){
        System.out.println("响应重定向");
//重定向项目下的路径
return "redirect:/jsp/index";
    }
//响应重定向
@GetMapping("redirect2")
    public String redirect2(){
        System.out.println("响应重定向");
//重定向项目外的路径
return "redirect:<http://www.baidu.com>";
    }

路径细节:

  1. 请求转发是项目下的资源跳转。路径要写为项目下的地址,忽略项目根路径
  2. 响应重定向是可以是项目下也可以是项目外的地址,在访问项目下的地址时不能忽略项目根路径
  3. 但是在springmvc下,响应重定向到项目下的地址时,springmvc会自动为其项目下的地址补上项目根路径

返回json数据

准备:导入json的依赖,并使用@EnableWebMvc注解写在配置类上

步骤:

  1. 将返回值类型设置为目标类型
  2. 在handler方法上方加上@ResponseBody注解,表示不找视图解析器,直接放入请求体,可以加在类上,表示该类下的所有handler方法都加上@ResponseBody注解
  3. 直接返回目标类型的对象即可,handlerAdapter会自动将其对象转化为json字符串。如果返回的是集合,同样会将其集合转化为json字符串

例:

@Controller
@RequestMapping("json")
public class JsonController {
    @GetMapping("data")
    @ResponseBody
    public User data(){
        User user = new User();
        user.setName("ergou");
        user.setAge(19);
        return user;
    }
    @GetMapping("data2")
    @ResponseBody
    public List<User> data2(){
        User user1 = new User();
        user1.setName("Tom");
        user1.setAge(20);

        User user2 = new User();
        user2.setName("Tony");
        user2.setAge(17);

        User user3 = new User();
        user3.setName("Rose");
        user3.setAge(18);

        List<User> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);
        users.add(user3);

        return users;
    }
}

拓展:@RestController=@Controller+@ResponseBody

静态资源处理

准备:配置类要实现WebMvcConfigurer接口

在配置类中实现configureDefalutServletHandling方法,调用参数configurer的enable方法即可

如此在dispatcherServlet通过一个路径去handlerMapping中找对应的handler方法没找到时,就会继续通过此路径去找静态资源

/**
 * mvc组件的配置类
*/
@Configuration
@ComponentScan("com.ergou")
@EnableWebMvc
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
//registry可以快速添加前后缀
registry.jsp("/WEB-INF/views/",".jsp");
    }

    //开启动态资源处理
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

RESTful

介绍

RESTful(Representational State Transfer)是一种软件架构风格,用于设计网络应用程序和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量级的通信协议,广泛应用于现代的Web服务开发。

通过遵循 RESTful 架构的设计原则,可以构建出易于理解、可扩展、松耦合和可重用的 Web 服务。RESTful API 的特点是简单、清晰,并且易于使用和理解,它们使用标准的 HTTP 方法和状态码进行通信,不需要额外的协议和中间件。

总而言之,RESTful 是一种基于 HTTP 和标准化的设计原则的软件架构风格,用于设计和实现可靠、可扩展和易于集成的 Web 服务和应用程序

restful-->更好地设计路径、设计参数传递、选择请求方式

restful特点

  1. 每一个URI代表1种资源(URI 是名词);

  2. 客户端使用GET、POST、PUT、DELETE 4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;

  3. 资源的表现形式是XML或者JSON

  4. 客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。

  5. HTTP协议请求方式要求

    REST 风格主张在项目设计、开发过程中,具体的操作符合HTTP协议定义的请求方式的语义

操作请求方式
查询操作GET
保存操作POST
删除操作DELETE
更新操作PUT
  1. URL路径风格要求

    REST风格下每个资源都应该有一个唯一的标识符,例如一个 URI(统一资源标识符)或者一个 URL(统一资源定位符)。资源的标识符应该能明确地说明该资源的信息,同时也应该是可被理解和解释的

    使用URL+请求方式确定具体的动作,也是一种标准的HTTP协议请求

操作传统风格REST 风格
保存/CRUD/saveEmpURL 地址:/CRUD/emp 请求方式:POST
删除/CRUD/removeEmp?empId=2URL 地址:/CRUD/emp/2 请求方式:DELETE
更新/CRUD/updateEmpURL 地址:/CRUD/emp 请求方式:PUT
查询/CRUD/editEmp?empId=2URL 地址:/CRUD/emp/2 请求方式:GET
  • 总结

    根据接口的具体动作,选择具体的HTTP协议请求方式

    路径设计从原来携带动标识,改成名词,对应资源的唯一标识即可

注:

在 RESTful API 的设计中,路径和请求参数和请求体都是用来向服务器传递信息的方式。

  • 对于查询用户详情,使用路径传递参数是因为这是一个单一资源的查询,即查询一条用户记录。使用路径参数可以明确指定所请求的资源,便于服务器定位并返回对应的资源,也符合 RESTful 风格的要求。
  • 而对于多条件模糊查询,使用请求参数传递参数是因为这是一个资源集合的查询,即查询多条用户记录。使用请求参数可以通过组合不同参数来限制查询结果,路径参数的组合和排列可能会很多,不如使用请求参数更加灵活和简洁。

此外,还有一些通用的原则可以遵循:

  • 路径参数应该用于指定资源的唯一标识或者 ID而请求参数应该用于指定查询条件或者操作参数
  • 请求参数应该限制在 10 个以内,过多的请求参数可能导致接口难以维护和使用。
  • 对于敏感信息,最好使用 POST 和请求体来传递参数

例:

@Controller
@ResponseBody
@RequestMapping("user")
public class UserController {
    @GetMapping
    public List<User> page(@RequestParam(required = false,defaultValue = "1") int page,
                           @RequestParam(required = false,defaultValue = "10") int size){
        System.out.println("page = " + page + ", size = " + size);
        return null;
    }
    @PostMapping    //接收json数据使用@RequestBody注解在形参前
    public User save(@RequestBody User user){
        return user;
    }
    @GetMapping("{id}")
    public User query(@PathVariable Integer id){
        return null;
    }
    @PutMapping
    public User update(@RequestBody User user){
        return user;
    }
    @GetMapping("search")
    public List<User> search(String keywork,
                             @RequestParam(required = false,defaultValue = "1") int page,
                             @RequestParam(required = false,defaultValue = "10") int size){
        return null;
    }
}

全局异常处理机制

关于异常处理

对于异常的处理,一般分为两种方式:

  • 编程式异常处理:是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。
  • 声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws@ExceptionHandler),就可以处理特定类型的异常。相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。

声明式异常的步骤

  1. 声明异常处理控制器类
    1. 在此类上加上指定注解,@RestControllerAdvice,@RestControllerAdvice等同于@ControllerAdvice注解加上@ResponseBody注解。全局异常发生时,会走此类写的handler方法。@ControllerAdvice 代表当前类的异常处理controller,@ResponseBody注解代表当前类的handler方法直接返回异常的json字符串。
  2. 声明异常处理handler方法
    1. 在类中创建handler方法,返回值类型为Object,在此方法上方加上@ExceptionHandler注解,在此注解中指定此方法处理的异常类型(写入异常类型的class实例,如果有多个,就用{}括号括起来),获取异常对象只要在形参列表中写一个对应异常类型的形参,使用其形参即可。
    2. 如果找异常handler方法时,没找到处理对应异常类型的handler方法,就会找处理其父类异常类型的handler方法。

注:要把异常处理控制器的类的包也加入ioc的包扫描下,才能生效

例:

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler({ArithmeticException.class, IOException.class})
    public Object ArithmeticExceptionHandler(ArithmeticException e){
        String message = e.getMessage();
        System.out.println(message);
        return message;
    }
    @ExceptionHandler(Exception.class)
    public Object ExceptionHandler(Exception e){
        String message = e.getMessage();
        System.out.println(message);
        return message;
    }
}

拦截器

拦截器比起过滤器,过滤器能够拦截到的最大范围是整个 Web 应用,拦截器能够拦截到的最大范围是整个 SpringMVC 负责的请求。过滤器能处理的没有拦截器能处理的细致,通常能用拦截器就使用拦截器。

拦截器的使用

  1. 写拦截类

    1. 创建一个类,这个类要实现HandlerInterceptor接口
    2. 在拦截类中重写拦截方法,可重写的拦截方法分为三种:
      1. preHandler方法:在目标handler方法之前执行
      2. postHandler方法:目标handler方法之后执行,若目标handler方法报错,则不会执行postHandler方法
      3. afterCompletion方法:最后执行的方法,即dispatcherServlet要将响应返回给客户端之前执行
    3. preHandler拦截方法的参数和返回值:
      1. 参数:request,代表请求对象
      2. 参数:response,代表响应对象
      3. 参数:handler,代表要调用的handler方法的对象
      4. 返回值:返回的结果为true则放行,返回的结果为false则拦截不放行
    4. postHandler拦截方法没有返回值,为void返回值类型的方法。相比preHandler方法的参数,参数多了一个modelAndView,代表着返回的视图和共享域对象。
    5. afterCompletion方法也没有返回值,为void返回值类型的方法。相比preHandle方法的参数,参数多了一个ex对象,代表异常信息的异常对象

    在拦截方法中写具体的拦截的逻辑代码即可

    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("request = " + request + ", response = " + response + ", handler = " + handler);
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", modelAndView = " + modelAndView);
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", ex = " + ex);
    
        }
    
  2. 配置拦截类

在配置类中重写addInterceptors方法(配置类实现了WebMvcConfigurer接口前提下),再调用registry参数的addInterceptor方法,在参数中传入拦截类的实例对象即可(可以直接在参数列表new一个拦截器的实例对象)

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyInterceptor());
}

指定地址拦截

在调用完addInterceptor方法后,再接着在后面调用addPathPattern方法,在addPathPattern方法参数列表中写要指定拦截的路径的字符串即可,可以使用模糊路径

@Override
    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new MyInterceptor());
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/data");
    }

排除拦截

在全部拦截或指定地址拦截后,再接着再后面调用excludePathPatterns方法,在excludePathPattern方法参数列表中写入要排除拦截的路径的字符串即可,可以使用模糊路径

@Override
    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new MyInterceptor());
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/**").excludePathPatterns("user/data1");
    }

多个拦截器执行顺序

  1. preHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置顺序调用各个 preHandle() 方法。
  2. postHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 postHandle() 方法。
  3. afterCompletion() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 afterCompletion() 方法。

参数校验

与参数校验有关的注解:(来自jsr303)

将其注解写在接收前端的数据的相关的实体类的属性上即可

注解规则
@Null标注值必须为 null
@NotNull标注值不可为 null
@AssertTrue标注值必须为 true
@AssertFalse标注值必须为 false
@Min(value)标注值必须大于或等于 value
@Max(value)标注值必须小于或等于 value
@DecimalMin(value)标注值必须大于或等于 value
@DecimalMax(value)标注值必须小于或等于 value
@Size(max,min)标注值大小必须在 max 和 min 限定的范围内
@Digits(integer,fratction)标注值值必须是一个数字,且必须在可接受的范围内
@Past标注值只能用于日期型,且必须是过去的日期
@Future标注值只能用于日期型,且必须是将来的日期
@Pattern(value)标注值必须符合指定的正则表达式
@Email标注值必须是格式正确的 Email 地址
@Length标注值字符串大小必须在指定的范围内
@NotEmpty标注值字符串不能是空字符串
@Range标注值必须在指定的范围内

注:

  1. @NotNull (包装类型不为null)

    @NotNull 注解是 JSR 303 规范中定义的注解,当被标注的字段值为 null 时,会认为校验失败而抛出异常。该注解不能用于字符串类型的校验,若要对字符串进行校验,应该使用 @NotBlank 或 @NotEmpty 注解。

  2. @NotEmpty (集合类型长度大于0)

    @NotEmpty 注解同样是 JSR 303 规范中定义的注解,对于 CharSequence、Collection、Map 或者数组对象类型的属性进行校验,校验时会检查该属性是否为 Null 或者 size()==0,如果是的话就会校验失败。但是对于其他类型的属性,该注解无效。需要注意的是只校验空格前后的字符串,如果该字符串中间只有空格,不会被认为是空字符串,校验不会失败。

  3. @NotBlank (字符串,不为null,切不为" "字符串)

    @NotBlank 注解是 Hibernate Validator 附加的注解,对于字符串类型的属性进行校验,校验时会检查该属性是否为 Null 或 “” 或者只包含空格,如果是的话就会校验失败。需要注意的是,@NotBlank 注解只能用于字符串类型的校验。

    校验的步骤

    • 在相应的注解上加上指定的校验注解

    例:

    @Data
    public class User {
        @NotBlank
        private String name;
        @Length(min = 6)
        private String password;
        @Min(1)
        private int age;
        @Email
        private String email;
        @Past
        private Date birthday;
    }
    
    • 在控制层的handler方法使用其实体类接收请求的数据时,在参数列表的其实体类类型的参数前,要加上@Validated注解
    @PostMapping("register")
    public User register(@Validated @RequestBody User user){
        System.out.println("user = " + user);
        return user;
    }
    
    • 设置错误绑定信息的捕捉,在handler方法的参数列表中,在要校验的对象后加上一个BindingResult类型的对象(BindingResult类型的对象必须跟在要校验的对象后面),在handler方法中加上一个if(result.hasErrors()){ }的条件语句,在条件语句中写发生错误绑定信息后的逻辑处理的代码

    例:

    @PostMapping("register")
    public Object register(@Validated @RequestBody User user, BindingResult result){
        if (result.hasErrors()) {
            Map data = new HashMap();
            data.put("code",400);
            data.put("msg","参数校验异常");
            return data;
        }
        System.out.println("user = " + user);
        return user;
    }
    

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二狗mao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值