目录
请求处理
1、请求参数处理
1、SpringMVC对请求参数的处理
2、乱码问题的解决
3、SpringMVC对原生API的支持
2、请求映射处理
1、@RequestMapping
2、@PathVariable
3、REST
4、静态资源的访问
在之前的servlet中我们可以通过request.getParameter()来获取请求中的参数,但是在我们编写的SpringMVC的应用程序中,在具体请求的方法中并不包含request参数,那么我们应该如何获取请求中的参数呢?
需要使用以下几个注解:
@RequestParam:获取请求的参数
@RequestHeader:获取请求头信息
@CookieValue:获取cookie中的值
@RequestParam的基本使用
jsp:
简单参数演示
package com.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 处理请求参数
* 之前servlet request.getParameter("name")
* 在springmvc中只需要在处理方法中声明对应的参数就可以自动接收请求的参数并且还可以自动转换类型
* 如果类型未匹配会报400错误
* 匹配规则
* 请求的参数必须跟处理方法的参数名一致
* 如果处理方法的参数未传入的情况会自动传入null
*
* 如果请求的参数跟处理方法的参数不一致
* 可以利用RequestParams
* @RequestParam 管理请求参数,用了这个注解之后默认必须要传入值否则报错
* value 用来重命名参数
* required 用来指定参数是否必须传入值
* true默认 必须传入 如果没有传入会报错400
* fale 可以不用传入值,如果没有传入会自动传入null
* 注意:不要用基础数据类型 因为基础类型无法接收null
* defaultValue 默认值,当参数为null时,会自动设置一个默认值
* 注意:当设置了默认值可以省略required=false
*/
@Controller
public class ParamsController {
@RequestMapping("/params01")
public String params01(@RequestParam(value="username",required = false,defaultValue = "456") String name){
System.out.println(name);
return "index.jsp";
}
}
@RequestHeader的基本使用:获取请求头中某个key的值。
@Controller
public class RequestController {
/**
* 如果需要获取请求头信息该如何处理呢?
* 可以使用@RequestHeader注解,
* public String header(@RequestHeader("User-Agent") String agent){
* 相当于 request.getHeader("User-Agent")
*
* 如果要获取请求头中没有的信息,那么此时会报错,同样,此注解中也包含三个参数,跟@RequestParam一样
* value
* required
* defalutValue
* @param agent
* @return
*/
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String agent){
System.out.println(agent);
return "success";
}
}
@CookieValue的基本使用
@Controller
public class RequestController {
/**
* 如果需要获取cookie信息该如何处理呢?
* 可以使用@CookieValue注解,
* public String cookie(@CookieValue("JSESSIONID") String id){
* 相当于
* Cookie[] cookies = request.getCookies();
* for(Cookie cookie : cookies){
* cookie.getValue();
* }
* 如果要获取cookie中没有的信息,那么此时会报错,同样,此注解中也包含三个参数,跟@RequestParam一样
* value
* required
* defalutValue
* @param id
* @return
*/
@RequestMapping("/cookie")
public String cookie(@CookieValue("JSESSIONID") String id){
System.out.println(id);
return "success";
}
}
复杂数据类型处理
JavaBean数据绑定
如果请求参数是POJO:
User类
package com.springmvc.entity;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class User {
private Integer id;
private String name;
private String [] alias;
private List hobbies;
private Map relatives;
private Role role;
private List friends;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", alias=" + Arrays.toString(alias) +
", hobbies=" + hobbies +
", relatives=" + relatives +
", role=" + role +
", friends=" + friends +
'}';
}
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[] getAlias() {
return alias;
}
public void setAlias(String[] alias) {
this.alias = alias;
}
public List getHobbies() {
return hobbies;
}
public void setHobbies(List hobbies) {
this.hobbies = hobbies;
}
public Map getRelatives() {
return relatives;
}
public void setRelatives(Map relatives) {
this.relatives = relatives;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public List getFriends() {
return friends;
}
public void setFriends(List friends) {
this.friends = friends;
}
}
Role类
package com.springmvc.entity;
public class Role {
private Integer id;
private String name;
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;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
增加控制器方法:
/**
* 复杂数据类型参数自动绑定演示
* 对象:
* 不用加上主参数名字的,直接传入该对象对应的属性名字
* 如果是包装类型的简单变量 直接输入属性名字= 表单元素的name : name="id"
* 数组 =保证这一组的表单元素都是同样的name: name="alias"
* List: 必须加上[索引] name="list[0]" 如果List : name="list[0].name"
* map: 必须加上[key] name="map["key"]"
* 实体类: 只能给某个属性去赋值 name="object.xxx"
*
*
* @param user
* @return
*/
@RequestMapping("/params02")
public String params02(User user){
System.out.println(user);
return "index.jsp";
}
params.jsp
复杂类型参数演示--User
测试
提交后,控制台打印
如果请求有多个对象(User user,Role role),建议再次封装一层javaBean
UserDTO类
package com.springmvc.entity;
public class UserDTO {
private User user;
private Role role;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
@Override
public String toString() {
return "UserDTO{" +
"user=" + user +
", role=" + role +
'}';
}
}
/**
* 复杂数据类型参数自动绑定演示 如果是List必须再使用JavaBean封装一层
* 注意:
* 如果出现多个对象比如:(User user,Role role)
* : (List)
* 参数的情况 建议再次封装一层javaBean (DTO data transfer object)
*
* @param userDTO
* @return
*/
@RequestMapping("/params03")
public String params03(UserDTO userDTO){
System.out.println(userDTO);
return "index.jsp";
}
复杂类型参数演示--List
如果是是List
springMVC参数绑定---集合类型
我们在表单或者发送请求的时候,经常会遇到中文乱码的问题,那么如何解决乱码问题呢?
GET请求:在server.xml文件中,添加URIEncoding=“UTF-8”
POST请求:编写过滤器进行实现
SpringMVC提供了一个CharacterEncodingFilter,将其配置在web.xml中可以解决POST请求乱码问题:
CharacterEncodingFilter
encoding参数:配置指定的字符集。
forceEncoding参数:设置为true表示同时开启请求和响应的编码。
characterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
characterEncodingFilter
springmvc
注意:如果配置了多个过滤器,那么字符编码过滤器一定要在最前面,否则失效。
Handler方法可以接收的ServletAPI还有:
HttpServletRequest
HttpServletResponse
HttpSession
java.security.Principal
Locale:国际化有关的区域信息对象。
InputStream:ServletInputStream inputStream = request.getInputStream();
OutputStream:ServletOutputStream outputStream = response.getOutputStream();
Reader:BufferedReader reader = request.getReader();
Writer:PrintWriter writer = response.getWriter();
/**
* SpringMVC也可以在参数上使用原生的Servlet API
*
* HttpSession
* HttpServletRequest
* HttpServletResponse
*
* java.security.Principal 安全协议相关
* Locale:国际化相关的区域信息对象
* InputStream:
* ServletInputStream inputStream = request.getInputStream();
* OutputStream:
* ServletOutputStream outputStream = response.getOutputStream();
* Reader:
* BufferedReader reader = request.getReader();
* Writer:
* PrintWriter writer = response.getWriter();
* @param session
* @param request
* @param response
* @return
*/
@RequestMapping("api")
public String api(HttpSession session, HttpServletRequest request, HttpServletResponse response){
request.setAttribute("requestParam","request");
session.setAttribute("sessionParam","session");
return "success";
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
成功666
请求域中的值:${requestScope.reqParam}
session域中的值:${sessionScope.sessionParam}
@RequestMapping用来匹配客户端发送的请求,可以在方法上使用,也可以在类上使用。
方法:表示用来匹配要处理的请求
类上:表示为当前类的所有方法的请求地址添加一个前置路径,访问的时候必须要添加此路径
package cn.tulingxueyuan.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/***
*
* @RequestMapping 用来处理URL映射 将请求映射到处理方法中
* 除了可以用在方法上面 还可以同时用在类上面:
* 将请求URL模块化
* 避免请求方法映射中的映射重复
* 如果加在类上面,该类所有请求方法的映射都必须加上类的映射:@RequestMapping("/mapping") /mapping/xxxx
* value 设置请求URL映射
* method 设置请求方式 GET/POST
* HTTP Status 405 - Request method 'GET' not supported
* 可以设置多个请求方式:method = {RequestMethod.POST,RequestMethod.GET}
* 如果不写就可以匹配所有请求方式
* 从spring4.3开始提供了一套简写请求方式的注解
* @PostMapping("mapping02")
* @GetMapping
* @PutMapping
* @DeleteMapping
*
* params : 设置请求必须携带某些参数
* 1. 必须要有某些参数 params = {"username"}
* 2. 必须没有某些参数 params = {"!username"}
* 3. 参数必须要等于什么值 params = {"username=范子天星"}
* 4. 参数必须要不等于什么值 params = {"username!=范子天星"}
* headers: 请求头必须包含某个值:headers = {"Accept-Language=zh-CN,zh;q=0.9"}
* consumes: 当前请求的内容类型必须为指定值
* 常见请求内容类型:
* application/x-www-form-urlencoded form表单提交默认的内容类型
* multipart/form-data form表单提交文件流的的内容类型
* application/json ajax提交的json内容类型
* 请求内容类型不匹配:HTTP Status 415 -
* consumes = {"application/x-www-form-urlencoded"}
*
*
* produces:设置当前响应的内容类型:produces = {"application/json"}
*
*
* 映射的URL还可以支持通配符 /ANT style
* 1.? 一个?匹配单个字符(a-z0-9)[1]
* 2.* 一个*匹配任意个字符(a-z0-9)[任意个]
* 3.** **匹配任意个字符任意层次 /** /
*
* 如果映射存在包含关系会优先交给更精确的那个映射处理
* 没有通配符>?>*>**
* 假如有4个映射处理方法:
* ant ant? ant* /** /ant
*
* http://localhost:8080/springmvc/mapping/ant ant处理
* http://localhost:8080/springmvc/mapping/ant1 ant?处理
* http://localhost:8080/springmvc/mapping/ant123 ant*处理
*
*
*/
@Controller
@RequestMapping("/mapping")
public class MappingController {
@RequestMapping("/mapping01")
public String mapping01(){
System.out.println("映射成功!");
return "/index.jsp";
}
//@RequestMapping(value="/mapping02",method = {RequestMethod.POST})
@PostMapping("/method") // 等同于上面的
public String mapping02(){
System.out.println("请求方式映射!");
return "/index.jsp";
}
@RequestMapping(value="/params",params = {"username!=范子天星"})
public String mapping03(){
System.out.println("请求参数映射!");
return "/index.jsp";
}
@RequestMapping(value="/headers",headers = {"Accept-Language=zh-CN,zh;q=0.9"})
public String mapping04(){
System.out.println("请求头映射!");
return "/index.jsp";
}
@RequestMapping(value="/consumes",consumes = {"application/x-www-form-urlencoded"})
public String mapping05(){
System.out.println("请求内容类型映射!");
return "/index.jsp";
}
@RequestMapping(value="/produces",produces = {"application/json"})
public String mapping06(){
System.out.println("响应的内容类型!");
return "/index.jsp";
}
// localhost:8080/springmvc/mapping/ant1
@RequestMapping(value="/ant*")
public String mapping08(){
System.out.println("通配符——*");
return "/index.jsp";
}
@RequestMapping(value="/ant?")
public String mapping07(){
System.out.println("通配符——?");
return "/index.jsp";
}
@RequestMapping(value="/**/ant")
public String mapping09(){
System.out.println("通配符——**");
return "/index.jsp";
}
}
注意:在整个项目的不同方法上不能包含相同的@RequestMapping值
除此以外,@RequestMapping注解还可以添加很多额外的属性值,用来精确匹配请求
如果需要在请求路径中的参数像作为参数应该怎么使用呢?可以使用@PathVariable注解,此注解就是提供了对占位符URL的支持,就是将URL中占位符参数绑定到控制器处理方法的参数中。
/***
*
* @PathVariable 用在参数上面的
* 专门用来获取URL目录级别的参数
* 比如 http://localhost:8080/springmvc/path/user/123/fztx
* 要获得123 @RequestMapping("/user/{id}") : @PathVariable("id") Integer id
*
* 如果是单个参数接收必须要使用@PathVariable来声明对应的参数占位符名字
* 如果是javaBean可以省略@PathVariable,要保证占位符的名字和javaBean的属性名字一样
*
*/
@Controller
@RequestMapping("/path")
public class PathvariableController {
/**
* 获取用户实体 传入id
* @return
*/
@RequestMapping("/user/{id}/{username}")
public String path01(@PathVariable("id") Integer id,@PathVariable("username") String name){
System.out.println(id);
System.out.println(name);
return "/index.jsp";
}
@RequestMapping("/user02/{id}/{name}")
public String path02(User user){
System.out.println(user);
return "/index.jsp";
}
}
客户端映射到服务器资源的一种架构设计
URL
restful
一种优雅的URL风格:
万维网 http协议 http://www.tulingxueyuan.cn
混乱:每一个都有一套自己的命名风格
根据id查询一个用户
user/getuser.do?id=1
user.do?action=getUser&id=1
user.do?action=a&id=xx
user/chaxunyonghu?id=1
user/CXYH?id=1
user/tulingxueyuan_cxyh?id=1
user/a.do?action=b?c=xx
REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。
一种相较与之前URL所产生一种更优雅的URL风格
URL CRUD
如果是原来的架构风格,需要发送四个请求,分别是?
查询用户:http://localhost:8080/app/user.do?action=getUser&id=xxx GET
增加用户: http://localhost:8080/app/user_add.do POST
修改用户: http://localhost:8080/app/xiugaiuser.do POST
删除用户: http://localhost:8080/app/delete.do?id=1 GET/POST
按照此方式发送请求的时候比较麻烦,需要定义多种请求,而在HTTP协议中,有不同的发送请求的方式,分别是GET、POST、PUT、DELETE等,我们如果能让不同的请求方式表示不同的请求类型就可以简化我们的查询,改成名词:
面向资源
看URL就知道要什么,, 看http method就知道干什么
查询用户: http://localhost:8080/xxx/user/1 GET --查询
查询多个用户: http://localhost:8080/xxx/users GET
新增用户: http://localhost:8080/xxx/user POST ---新增
修改用户: http://localhost:8080/xxx/user/1 PUT --修改
删除用户:http://localhost:8080/xxx/user/1 DELETE --删除
一切看起来都非常美好,但是大家需要注意了,我们在发送请求的时候只能发送post或者get,没有办法发送put和delete请求,那么应该如何处理呢?下面开始进入代码环节:
@Controller
public class RestController {
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String add(){
System.out.println("添加");
return "success";
}
@RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)
public String delete(@PathVariable("id") Integer id){
System.out.println("删除:"+id);
return "success";
}
@RequestMapping(value = "/user/{id}",method = RequestMethod.PUT)
public String update(@PathVariable("id") Integer id){
System.out.println("更新:"+id);
return "success";
}
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
public String query(@PathVariable("id") Integer id){
System.out.println("查询:"+id);
return "success";
}
}
或者
/***
*
* 用户rest风格CRUD
*
* form表单提交PUT和DELETE出现问题:会将PUT和DELETE作为GET提交,因为HTML现在无法支持PUT和DELETE:
* 解决:1.需要添加HiddenHttpMethodFilter过滤器
* 2.在表单中添加一个有隐藏域 value就是对应的请求方式
* 3.将form的method设置POST
* 4.过滤器就会自动将POST请求修改成隐藏域中对应值的请求
*
*
* tomcat 7以上的版本对request.method更加严格:只支持GET/POST/HEAD:
* HTTP Status 405 - JSPs only permit GET POST or HEAD
* 1.用tomcat7
* 2.不用转发,用重定向
* 3. 将jsp的page指定 isErrorPage属性改成true(不建议)
* 4. 自定义一个过滤器,将request.method改回POST
*/
@Controller
@RequestMapping("/rest")
public class RestController {
// 查询
@GetMapping("/user/{id}")
public String get(@PathVariable("id") Integer id){
System.out.println("查询用户:"+id);
return "/index.jsp";
}
// 新增
@PostMapping("/user")
public String add(User user){
System.out.println("新增用户:"+user);
return "/index.jsp";
}
// 修改
@PutMapping("/user/{id}")
public String update(User user){
System.out.println("修改用户:"+user);
return "/index.jsp";
}
// 删除
@DeleteMapping("/user/{id}")
public String delete(@PathVariable("id") Integer id){
System.out.println("删除用户:"+id);
return "/index.jsp";
}
}
web.xml
hiddenFilter
org.springframework.web.filter.HiddenHttpMethodFilter
hiddenFilter
/*
rest.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
查询
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
Title
666
解决:405错误的自定义过滤器
4种解决方式:
* 1.用tomcat7
* 2.不用转发,用重定向
* 3. 将jsp的page指定 isErrorPage属性改成true(不建议)
* 4. 自定义一个过滤器,将request.method改回POST
public class GetMethodConvertingFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
// do nothing
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(wrapRequest((HttpServletRequest) request), response);
}
@Override
public void destroy() {
// do nothing
}
private static HttpServletRequestWrapper wrapRequest(HttpServletRequest request) {
return new HttpServletRequestWrapper(request) {
@Override
public String getMethod() {
return "POST";
}
};
}
}
可以参考以下两篇文章
SpringMVC(RESTful风格)
利用Spring MVC实现RESTful风格
当页面中包含静态资源的时候我们能够正确的获取到吗?
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
pageContext.setAttribute("ctx",request.getContextPath());
%>
Title
hello springmvc
此时大家发现我们请求的图片根本访问不到,根据查看发现路径是没有问题的,那么为什么会找不到静态资源呢?
大家发现此时是找不到对应的mapping映射的,此时是因为DispatcherServlet会拦截所有的请求,而此时我们没有对应图片的请求处理方法,所以此时报错了,想要解决的话非常简单,只需要添加一个配置即可
但是加上此配置之后,大家又发现此时除了静态资源无法访问之外,我们正常的请求也无法获取了,因此还需要再添加另外的配置: