后端主流框架——03SpringMVC

目录

spring mvc

字符编码过滤器(可不配置)

Spring Bean 作用域

映射请求

获取一般参数 

1.@RequestParam

2.@PathVariable

参数格式处理

获取特殊参数

实体对象属性校验


spring mvc

使用 spring mvc 主要解决之前 Servlet 冗余的问题,通常使用 maven 的 web 项目,并导入相关依赖。关于 MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式,这种模式用于应用程序的分层开发。

Model(模型)- 模型代表一个存取数据的对象或 JAVA POJO(entity)。它也可以带有逻辑,在数据变化时更新控制器。

View(视图) - 视图代表模型包含的数据的可视化。

Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

1.加入依赖


    org.springframework
    spring-webmvc
    5.2.12.RELEASE


    com.fasterxml.jackson.core
    jackson-databind
    2.12.3

依赖关系:

后端主流框架——03SpringMVC_第1张图片

注意:jackson 是全世界现今非常主流且性能非常好的对象序列化 json 与反序列化类库。与国内的阿里巴巴的 fastjson 相媲美。

2.在 web.xml 配置 DispatcherServlet,用来匹配所有请求,并指定它的创建时机为 web 应用启动时。


    springDispatcherServlet
    org.springframework.web.servlet.DispatcherServlet
    
        contextConfigLocation
        classpath:spring-mvc.xml
    
    1


    springDispatcherServlet
    /

 3.在 resource 下创建 spring-mvc.xml 文件,内容如下:




    
    
    
    
    
    
    
    
        
        
        
        
    

注意:包扫描也可以使用如下方式扫描指定的注解。凡是 Controller 与 ControllerAdvice 注解的都扫描为 spring mvc 的


    
    

4编写控制器

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

    @RequestMapping("/index")
    public String index() {
        System.out.println("index");
        return "index";
    }
}

如上操作即可完成 spring mvc 的配置,当浏览器客户端发送请求时,会被 web.xml 中的 springDispatcherServlet 匹配上,请求就进入 spring mvc 内部,内部会将所有的 RequestMapping 的路径与请求路径匹配,如果匹配便会调用方法,最后获取方法的返回值与 internalResourceViewResolver 的前缀和后缀拼接,转发到对应视图,将视图返回浏览器客户端。

在 spring mvc 中重定向非常简单只需要在返回字符串前拼接 redirect 关键字即可,如果没有该关键字就是转发。

@GetMapping("aa/bb")
public String index() {
    return "redirect:/index";
}

字符编码过滤器(可不配置)

在前面的 jsp Servlet 开发中遇到中文乱码时比较实用的解决办法是使用过滤器统一编码,使用过滤器可以解决服务端和客户端之间的中文字符编码不统一的问题。在 web.xml 中加入由 spring-mvc 提供的字符编码过滤器器 CharacterEncodingFilter,并为该拦截器配置初始化参数 encoding 为 utf-8 即可使所有的请求和响应都以 utf-8 的编码传输。


    characterEncodingFilter
    org.springframework.web.filter.CharacterEncodingFilter
    
        encoding
        UTF-8
    


    characterEncodingFilter
    /*

Spring Bean 作用域

在 Spring 中介绍过 bean 的作用域有单例和多例,为了适应 web 开发 Spring mvc 对其进行了扩展。将 Bean 定义了 5 中作用域,分别为 singleton(单例)、prototype(原型)、 request、session 和 global session,5 种作用域。

1. singleton:单例模式,Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个 Bean 引用它,始终指向同一对象。该模式在多线程下是不安全的。Singleton 作用域是 Spring 中的默认的作用域。

2. prototype:原型模式,每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建 一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态,而 singleton 全局只有一个对 象。根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton 作用域。

3. request:在一次 Http 请求中,容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会 产生新的 Bean,而且该 bean 仅在当前 Http Request 内有效,当前 Http 请求结束,该 bean 实例也将会被销毁。

4. session:在一次 Http Session 中,容器会返回该 Bean 的同一实例。而对不同的 Session 请求则会创建新的实例,该 bean 实例仅在当前 Session 内有效。同 Http 请求相同,每一次 session 请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的 session 请求内有效,请求结束,则实例将被销毁。

5. global Session:在一个全局的 Http Session 中,容器会返回该 Bean 的同一个实例,仅在使用 portlet context 时有效。

映射请求

在 spring mvc 中使用 @RequestMapping 注解用来映射对应的请求路径,与 servlet 中注解的地址作用相同。该注解可以修饰类和方法,但是它没有 servlet 地址那么严格需要以斜杠开头。

修饰类:提供初步的请求映射信息,也就是请求的父路径。

方法处:提供进一步的细分映射信息。叠加类定义处的 URL。若类定义处未标注则是自己的 URL。

使用 method 属性来指定请求方式,也可以简写使用 @PostMapping,与下面的等效。

@RequestMapping(value = "/testMethod", method = RequestMethod.POST)

可以使用 params 和 headers 来更加精确的映射请求。params 和 headers 支持简单的表达式

@RequestMapping(value = "testParamsAndHeaders", params = { "username","age!=10" }, headers = { "Accept-Language=en-US,zh;q=0.8" })

请求参数和请求头必须满足对应的要求才能调用,否则将不能调用该接口。

@RequestMapping 中支持通配符

@RequestMapping("/testAntPath/*/abc")

? 匹配一个字符

* 匹文件名中任意字符串(但不包括/)

** 匹配多层路径

注意:spring MVC 接口方法参数支持 servlet 中的常用对象,如 request、response、session 等,框架会自动从 Tomcat 容器中获取该对象注入到形参的位置。

  • HttpServletRequest 
  • HttpServletResponse 
  • HttpSession 
  • java.security.Principal 
  • Locale 
  • InputStream 
  • OutputStream 
  • Reader 
  • Writer 

使用以上接口需要导入与本地tomcat版本一致的tomcat-jsp-api依赖 

获取一般参数 

spring MVC 极大的简化获取客户端浏览器参数的方式,开发人员不在需要 request 对象获取参数,一般的,只需要用户的方法参数名和前端传入的参数名对应,即可自动接收到对应参数,如果在参数名不一致时可以使用 RequestParam 注解进行映射,同时还可以使用该注解设置该参数必传且不为空,设置默认值等。

1.@RequestParam

如果方法的参数名与请求里面的键相同时可以省略。

@RequestMapping
public String testRequestParam(
        @RequestParam(value = "username") String un,
        @RequestParam(value = "age", defaultValue = "0") int age) {
   return "index";
}

@RequestParam 来映射请求参数. 

value 值即请求参数的参数名 

required 该参数是否必须,默认为 true

defaultValue 请求参数的默认值,如果参数有默认值,则 required 自动变为 false

还可以使用对象接受参数,spring MVC 会自动创建对象并将客户端参数设置到对应的对象中。

@RequestMapping
public String testPojo(User user) { 
    return "success"; 
}

 并且支持级联属性如:role.id、dept.address 等,该值会自动注入 user 里面的 role 和 dept 里面。

2.@PathVariable

在很多主流应用中,简单和少量的参数一般不采用问号拼接,而是直接拼接在接口的末尾。使用 @PathVariable 注解可以用来映射 URL 中的占位符到目标方法的参数。需要注意的是使用 @PathVariable 修饰的参数的方法在映射时优先级低于精确匹配的优先级。

@RequestMapping("/index/{id}")
public String testPathVariable(@PathVariable("id") Integer id) {
  System.out.println("testPathVariable: " + id);
}

注意:在使用 @PathVariable 注解时虽然优先级低于精确匹配但它的优先级会高于静态资源如静态资源为 /css/style.css 会被 @RequestMapping("{path}/{name}")映射,所以一般使用 @PathVariable 是都只获取最后一个测试即可。

参数格式处理

在前后端开发中,参数格式一直都是一个比较头疼的问题,就时间来说有使用 2021-1-28 17:33:16、2021/1/28、2021-1-28,使用 DateTimeFormat 注解可以很好的为前端数据注入时间指定对应的格式。同理在数学上有时数字会使用每隔 3 位加一个逗号等情况,使用 NumberFormat 注解完成数据格式处理。

案例:

@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;

案例:

1,456,333.5
@NumberFormat(pattern="#,###,###.#")
private Float salary;

指定前端时间注入格式还有另一种解决办法,使用 InitBinder 注解可以使整个类中的时间格式全部使用指定格式。

@RequestMapping("date")
public String date(Date date){
    System.out.println(date);
    return "hello";
}

@InitBinder
public void initBinder(ServletRequestDataBinder binder){
    binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),
        true));
}

获取特殊参数

在实际开发中经常会获取客户端浏览器请求头里面的某些参数,比较原始的方法是在接口方法参数中注入 request 对象,通过 request 对象获取请求头里面的参数。当然还可以通过注解 RequestHeader 获取请求头里面的参数。@RequestHeader 用法与 @RequestParam 类似,只是@RequestHeader 不能省略。

public String testRequestHeader(@RequestHeader(value = "Accept-Language") String al) {
    return al;
}

@CookieValue 可以获取请求头里面的一个 Cookie 值。用法与 @RequestParam 类似,只是 @CookieValue 也不能省略。

public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) {
    return SUCCESS;
}

实体对象属性校验

在实际开发中,用户参数校验是一项必不可少的开发逻辑,不但需要做到前端校验(使用 JavaScript 进行参数校验),后端获取到参数后也要做相应的校验。其中比较常用的一种是使用 hibernate 提供的一种通用的校验规范,在后面学习的 Springboot 框架中便是使用这一校验规则。

导入相关依赖


  org.hibernate
  hibernate-validator
  6.1.0.Final

实体上加入校验注解

@NotEmpty
private String lastName;

@Email
private String email;

@Past//当前时间的前面
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;

在需要校验的接口方法参数上加入校验注解,前端数据过来时就会自动校验。

@GetMapping(value = "/")
public String index2(@Validated User user, Errors result) {
    System.out.println("我被调用了" + user);
    for (FieldError error : result.getFieldErrors()) {
        System.out.println(error.getField() + ":" + error.getDefaultMessage());
    }
    return "hello";
}

分组校验:案例

import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Controller
public class PublicController {

    @GetMapping("/index")
    public String index() {
        return "index";
    }

    @PostMapping("login")
    public String login(@Validated(User.Login.class) User user) {
        System.out.println(user);
        return "index";
    }
    @PostMapping("register")
    public String register(@Validated(User.Register.class) User user) {
        System.out.println(user);
        return "index";
    }
}

class User{
    private Integer id;
    @NotBlank(groups = Register.class)
    private String name;
    @NotBlank(groups = {Register.class,Login.class})
    private String loginName;
    @NotBlank(groups = {Register.class,Login.class})
    private String loginPassword;
    @NotNull(groups = Register.class)
    private Integer classId;

    interface Register{}
    interface Login{}

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getLoginPassword() {
        return loginPassword;
    }

    public void setLoginPassword(String loginPassword) {
        this.loginPassword = loginPassword;
    }

    public Integer getClassId() {
        return classId;
    }

    public void setClassId(Integer classId) {
        this.classId = classId;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", loginName='" + loginName + '\'' +
                ", loginPassword='" + loginPassword + '\'' +
                ", classId=" + classId +
                '}';
    }
}

常用标签

@Null  被注释的元素必须为null
@NotNull  被注释的元素不能为null

@NotEmpty  @NotEmpty除了@NotNull之外还需要保证@Size(min=1),这也是一个注解,这里规定最小长度等 
            于1,也就是类似于集合非空。

@NotBlank   当一个string对象是null时方法返回true,但是当且仅当它的trimmed length等于零时返回 
           false。即使当string是null时该方法返回true,但是由于@NotBlank还包含了@NotNull,所以 
           @NotBlank要求string不为null

@AssertTrue  被注释的元素必须为true
@AssertFalse  被注释的元素必须为false
@Min(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max,min)  被注释的元素的大小必须在指定的范围内。
@Digits(integer,fraction)  被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past  被注释的元素必须是一个过去的日期
@Future  被注释的元素必须是一个将来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式。
@Email 被注释的元素必须是电子邮件地址
@Length 被注释的字符串的大小必须在指定的范围内
@NotEmpty  被注释的字符串必须非空
@Range  被注释的元素必须在合适的范围内

你可能感兴趣的:(java后端开发,spring,java,tomcat,maven,spring,boot)