SpringMVC | 基础(一)

SpringMVC | 基础(一)_第1张图片

一、简介

SpringMVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无需实现任何接口。支持 REST 风格的 URL 请求

二、搭建环境及HelloWorld

2.1 加入架包
  • commons-logging-1.2.jar
  • spring-aop-5.0.7.RELEASE.jar
  • spring-beans-5.0.7.RELEASE.jar
  • spring-context-5.0.7.RELEASE.jar
  • spring-core-5.0.7.RELEASE.jar
  • spring-expression-5.0.7.RELEASE.jar
  • spring-web-5.0.7.RELEASE.jar
  • spring-webmvc-5.0.7.RELEASE.jar

2.2 配置web.xml

配置 DispatcherServlet:默认加载 /WEB-INF/-servlet.xml 的 Spring 配置文件来启动 WEB 层的容器。同时也可以通过 contextConfigLocation 初始化参数自定义配置文件的位置和名称



    springDispatcherServlet
    org.springframework.web.servlet.DispatcherServlet
    
    
    
    
        contextConfigLocation
        classpath:springmvc.xml
    
    
    
    1



    springDispatcherServlet
    /

DispatcherServlet 的任务就是拦截请求发送给 Spring MVC 控制器

2.3 创建 SpringMVC 视图解析器


    


    
    

将视图逻辑名解析为:/WEB-INF/views/.jsp

2.4 创建请求处理器类
  1. 使用 @RequestMapping 注解来映射请求的 URL
  2. 返回值会通过视图解析器解析为实际的物理视图,对于 InternalResourceViewResolver 视图解析器,会做如下的解析:
    prefix + returnVal + suffix 这样的方式得到实际的物理视图,然后会做转发操作
@Controller     //请求处理器
public class HelloWorld {
    
    @RequestMapping("/helloworld")
    public String hello() {
        System.out.println("hello world");
        return "success";
    }

}

以上转发到 /WEB-INF/views/success.jsp 这个页面

三、具体使用

3.1 使用@RequestMapping映射请求

3.1.1

@RequestMapping 注解为控制器指定可以处理哪些 URL 请求,在类和方法都可以标注

  • 类定义:提供初步的请求映射信息。相对于 WEB 应用的根目录
  • 方法处:进一步细分映射信息。相对于类定义处的 URL,若类上面没有 @RequestMapping 注解,则方法处标记的 URL 相对于 WEB 应用的根目录

DispatcherServlet 截取请求后,就通过 @RequestMapping 提供的映射信息确认请求所对应的处理方法

@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
    
    private static final String SUCCESS = "success";

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

}

访问到此方法的地址是:WEB容器的根路径/springmvc/testRequestMapping,同时由于配置了视图解析器,因此直接转到 /WEB-INF/views/ 下的 success.jsp 页面

@RequestMapping 的 value、method、params 以及 heads 分别标识请求 URL、请求方法、请求参数以及请求头的映射条件,他们之间是与的关系

@RequestMapping(..., method=RequestMethod.POST)                //使用 method 属性来指定请求方式
@RequestMapping(..., params={"username", "age!=10"}, headers="Content-Type=text/html")          //使用 params 和 headers 

PS:用的比较少

3.1.2 使用 Ant 风格来写地址

?:匹配文件名中的一个字符
*:匹配文件名中的任意字符
**:匹配多层路径

/springmvc/test??? ——> /springmvc/testaaa
/springmvc/*/test ——> /springmvc/asv/test
/springmvc/**/test ——> /springmvc/aaa/bbb/test

PS:用的比较少

3.1.3 ⭐使用@PathVariable映射URL绑定的占位符

通过 @PathVariable 可以将 URL 占位符参数绑定到控制器处理方法的入参中

@RequestMapping("/testPathVariable/id={id123}")
public String testPathVariable(@PathVariable("id123") String id) {
    System.out.println(id);
    return SUCCESS;
}

URL 中的 {xxx} 占位符可以通过 @PathVariable("xxx") 绑定到操作方法的入参中。这个时候 @PathVariable 中的参数必须与占位符 {} 中的参数相同

@RequestMapping("/testPathVariable/id={id12}")
public String testPathVariable(@PathVariable String id12) {
    System.out.println(id12);
    return SUCCESS;
}

当然,也可以不用指定 @PathVariable 后面的参数,此时 {xxx} 占位符里面的参数可以直接绑定到控制器处理方法的入参中,但是两个参数必须相同

3.2 映射请求参数和请求参数

3.2.1 使用@RequestParam绑定请求参数值

@RequestParam 可以在后台获取从前台传过来的数据。
value:请求参数的参数名
required:该参数是否必须。默认为 true
defaultValue:请求参数的默认值

@RequestMapping(value="/testRequestParam")
public String testRequestParam(@RequestParam(value="username") String un,
        @RequestParam(value="age", required=false, defaultValue="0") Integer age) {
    System.out.println("testRequestParam: " + un + ",age: " + age);
    return SUCCESS;
}

上图获取从前台传过来的参数名为 usernameage 的值,其中 age 是可选的,如前台的地址是 ...?username=5&age=5

如果参数为 int 类型,且没有加默认的值,则会报错。两种修改的方式:1. 将 int 类型改为 Integer;2. 如果参数类型必须为 int,则添加默认值

3.2.2 使用POJO对象绑定请求参数值

SpringMvc 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值,支持级联属性。

前台代码

username:
password:
email:
city:

从后台获取前台传过来的数据

@RequestMapping("/testpojo")
public String testPojo(User user) {
    System.out.println("^^" + user);
    return SUCCESS;
}


3.2.3 使用Servlet API作为入参

包括HttpServletRequestHttpServletResponseHttpSessionPrincipalLocaleInputStreamOutputStreamReaderWriter

@RequestMapping("/testServletAPI")
public void testServletAPI(HttpServletRequest request, HttpServletResponse response, Writer out) throws IOException {
    System.out.println("testServletAPI, " + request + ", " + response);
    out.write("hello qorld");
}


3.3 处理模型数据(常用于回显操作)

3.3.1 ModelAndView

1.
springmvc 会把 ModelAndView 的 model 中数据放在 request 域对象中

/**
  * 目标方法的返回值可以是 ModelAndView 类型
  * 其中包含视图和模型信息
  * SpringMVC 会把 ModelAndView 的 model 中的数据放入到 request 域对象中
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
    String viewName = SUCCESS;
    ModelAndView modelAndView = new ModelAndView(viewName);
        
    //添加模型数据到 ModelAndView 中
    modelAndView.addObject("time", new Date());
        
    return modelAndView;
}

success.jsp

time: ${requestScope.time }

这里从 request 作用域中获取参数 time 对应的值

3.3.2 Map和Model
  1. SpringMVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器
  2. 如果方法的入参为 Map 或 Model 类型,SpringMVC 会将隐含模型的引用传递给这些入参

Map 方式

/**
  * 目标方法可以添加 Map(实际上也可以是 Model 类型或者 ModelMap 类型) 类型的参数
  */
@RequestMapping("/testMap")
public String testMap(Map map) {
    map.put("names", Arrays.asList("Tom", "Jerry", "Mike"));

    return SUCCESS;
}

success.jsp

map: ${requestScope.names }


Model 方式:比较常用

@RequestMapping("value")
public String test(Model model) {
    model.addAttribute("time", "hello");
    return SUCCESS;
}

success.jsp

time: ${requestScope.time }


3.3.3 @SessionAttributes

将模型中的某个属性暂存到 HttpSession 中,以便多个请求之间可以共享这个属性

@SessionAttribute 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中

  1. @SessionAttributes(types={User.class}) 会将隐含模型中类型为 User.class 的属性放到会话中
  2. @SessionAttributes(value={"user"}) 将名为 user 的模型属性添加到会话中
  3. @SessionAttribute(values={"user1", "user2"})
@SessionAttributes(value={"user"}, types={User.class})
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {

    private static final String SUCCESS = "success";
  
    @RequestMapping("/testSessionAttributes")
    public String testSessionAttributes(Map map) {
        User user = new User(null, "luwenhe", "lwh011305", "[email protected]");
        
        map.put("user", user);
        map.put("user1", "ni hao shi jie");
        return SUCCESS;
    }
}

PS:该注解只能放在类的上面,而不能修饰方法

session: ${sessionScope.user }
session1: ${sessionScope.user1 }


3.3.4 @ModelAttribute

方法上使用 @ModelAttribute 注解,SpringMVC 在调用目标方法之前,会先逐个调用在方法上标注了 @ModelAttribute 的方法

index.jsp:用于从表单中输入数据,模拟从数据库中获取数据

username:
email:

如果没用 @ModelAttribute 注解,则会输出 User [Id=1, username=Tom, password=null, [email protected]]

@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
    System.out.println("修改: " + user);
    return SUCCESS;
}

如果在上述代码之前加入标注了 @ModelAttribute 注解的方法,模拟修改了对象 User 的信息

@ModelAttribute
public void getUser(@RequestParam(value="id", required=false) Integer id,
            Map map) {      //从后台获取前台参数名字为 id 的元素的值
    System.out.println("id: " + id);
    if(id != null) {
        User user = new User(1, "Tom", "123", "[email protected]");
        System.out.println("从数据库中获取一个对象: " + user);
        
        map.put("user", user);
    }
}

最终的输出是:

id: 1
从数据库中获取一个对象: User [Id=1, username=Tom, password=123, [email protected]]
修改: User [Id=1, username=Tom, password=123, [email protected]]

可见 SpringMVC 从 Map 中取出 User 对象,并把对象传入了目标方法的参数中

注意:在 @ModelAttribute 修饰的方法中, 放入到 Map 时的键需要和目标方法参数的第一个字母小写的字符串一致, 如参数为 User, 则 Map 的键为 user

SpringMVC 确定目标方法 POJO 类型入参的过程:
1. 确定一个 key: 
   1). 若目标方法的 POJO 类型的参数没有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写
   2). 若使用了 @ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的属性值

2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入
   1). 若在 @ModelAttribute 标记的方法在 Map 中保存过, 且 key 和 1 确定的 key 一致, 则会获取到.

3. 若 implicitModel 不存在 key 对应的对象, 则检查当前的 Handler 是否使用 @SessionAttributes 注解修饰, 若使用了该注解, 
   且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所对应的 value 值, 
   若存在则直接传到目标方法的入参中, 若不存在则将抛出异常

4. 若 Handler 没有标识 @SessionAttribute 注解或 @SessionAttribute 注解的 value 
   值中不包含 key, 则会通过反射来创建 POJO 类型的参数, 传入为目标方法的参数, 此时只能获取从前台传过来的值

5. SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而保存到 request 中


3.4 视图和视图解析器

SpringMVC | 基础(一)_第2张图片
  • 请求方法执行完成后,最后返回一个 ModelAndView 对象。对于那些返回 String,View 或者 ModelMap 类型的方法,SpringMVC 会在内部将他们装配成一个 ModelAndView 对象
  • SpringMVC 接主视图解析器(ViewResolver)得到最终的视图对象 View,最终的视图可以是 JSP,也可以是其他类型

视图

视图的作用是渲染模型数据,将模型数据以某种形式呈现给客户。常见的视图实现类有:

  • InternalResourceView:将 JSP 或其他资源封装成一个视图,是 InternalResouceViewResolver 默认使用的视图实现类
  • JstlView:如果 JSP 文件中使用了 JSTL 国际化标签的功能,则需要使用该试图类
  • AbstractExcelView:Excel 文档视图的抽象类,用于构造 Excel 文档

视图解析器

所有视图解析器必须实现 ViewResovler 接口。常见的视图解析器类有:

  • BeanNameViewResolver:将逻辑视图名解析为一个 Bean,Bean 的 id 等于逻辑视图名
  • InternalResourceViewResolver:将视图名解析为一个 URL 文件


    


    
    


重定向

如果字符串中带有 forward: 或者 redirect,SpringMVC 会对他们做特殊处理,前者为转发操作,后者
为重定向

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

此代码会重定向到根目录下的 index.jsp 页面

3.5 使用RESTFul

REST 即 Representational State Tranfer,即表现层状态转化。
表现层(Representation):把资源具体呈现出来的形式。
状态转化(State Tranfer):每发出一个请求,就代表了客户端和服务器的一次交互。

如何发送 PUT 请求和 DELETE 请求?

  1. 需要配置 HiddenHttpMethodFilter
  2. 需要发送 POST 请求
  3. 需要在发送 POST 请求时携带一个 name="_method" 的隐藏域, 值为 DELETE 或 PUT

配置文件



    HiddenHttpMethodFilter
    org.springframework.web.filter.HiddenHttpMethodFilter

    

    HiddenHttpMethodFilter
    /*   

HiddenHttpMethodFilter:由于浏览器只支持 GET 和 POST,不支持 DELETE 和 PUT,因此此过滤器可以将请求转换为支持四种请求

前台页面:

从后台获取

@RequestMapping(value="/testRest/{id}", method=RequestMethod.DELETE)    //delete 方法
@ResponseBody
public String testRestDelete(@PathVariable Integer id) {
    System.out.println("testRest DELETE: " + id);
    return SUCCESS;
}

@ResponseBody 一开始没有加,会报错,百度之后由此加上

3.5 处理静态资源

若将 DispatcherServlet 请求映射配置为 /,则 SpringMVC 将捕获 WEB 容器的所有请求,包括静态资源的请求,SpringMVC 会将他们当成一个普通请求来处理,因此会找不到对应处理器而报错

解决方案:可以在 SpringMVC 的配置文件中配置 的方式

原理:
将在 SpringMVC 上下文定义一个 DefaultServletHttpRequestHandler,他会对进入 DispatcherServlet 的请求进行筛选,如果发现是没有经过映射的请求(@RequestMapping),就将请求交给 WEB 应用服务器的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理

此时还需要在配置文件中加入 才可以运行


    



关于

  1. 会自带注册 RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver 三个 Bean

  2. 同时提供以下支持:
    ①. 支持使用 ConversionService 实例对表单进行类型转换
    ②. 支持使用 @NumberFormat annotation@DateTimeFormat 注解完成数据类型的格式化
    ③. 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
    ④. 支持使用 @RequestBody@ResponseBody 注解

PS:一般情况下,都会配置 这个说明

3.6 数据绑定

SpringMVC | 基础(一)_第3张图片
数据绑定流程

核心是 DataBinder

  • DataBinder:调用装配在 SpringMVC 上下文的 ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中
  • Validator :对已经绑定了请求信息的入参对象进行数据合法性校验
  • BindingResult:SpringMVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

@InitBinder注解
  • @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的字类,用于完成由表单字段到 JavaBean 属性的绑定
  • @InitBinder 方法不能有返回值,必须声明为 void
  • @InitBinder 方法的参数通常是 WebDataBinder
@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setDisallowedFields("lastName");
}

以上代码表示不能绑定对象中的名为 lastName 的属性,造成的结果就是最后不能输出属性名为 lastName 字段的值

格式化操作

可以在定义的属性上面使用 @NumberFormat@DateTimeFormat 注解进行数据格式化

对数字进行格式化

@NumberFormat(pattern="###.#")
private Float salary;

对日期进行格式化

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

最后别忘了加上注解



五、参考

  • Spring MVC 流程图
  • Spring MVC【入门】就这一篇!

你可能感兴趣的:(SpringMVC | 基础(一))