Spring MVC 学习(2)—— REST、映射请求参数、处理数据模型

1. REST

概述

  • REST:即 Representational State Transfer。(资源)表现层状态转化。是目前流行的一种互联网软件架构。系统希望以非常简洁的URL地址来发请求,怎样表示对一个资源的增删改查用请求方式来区分
  • 资源(Resources):网络上的一个实体可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。
  • 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
  • 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源

Rest推荐URL地址命名方式:/资源名/资源标识符,并通过HTTP 协议四种不同请求方式区分对资源的操作

实现

HiddenHttpMethodFilter:浏览器 form 表单只支持 GETPOST 请求,而DELETEPUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUTDELETE 请求。

<filter>
		<filter-name>HiddenHttpMethodFilter</filter-name>
		<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>HiddenHttpMethodFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
<a href="book/1">查询图书</a><br/>

<!-- 发送POST请求 -->
<form action="book" method="post">
	<input type="submit" value="添加1号图书"/>
</form><br/>

<!-- 发送DELETE请求 -->
<form action="book/1" method="post">
	<input name="_method" value="delete"/>
	<input type="submit" value="删除1号图书"/>
</form><br/>

<!-- 发送PUT请求 -->
<form action="book/1" method="post">
	<input name="_method" value="put"/>
	<input type="submit" value="更新1号图书"/>
</form><br/>
@Controller
public class BookController extends HttpServlet{
	
	@RequestMapping(value="/book/{bid}", method=RequestMethod.GET)
	public String getBook(@PathVariable("bid")Integer bid){
		System.out.println("查询到了"+bid+"号图书");
		return "success";
	}
	
	@RequestMapping(value="/book/{bid}",method=RequestMethod.DELETE)
	public String deleteBook(@PathVariable("bid")Integer bid){
		System.out.println("删除了"+bid+"号图书");
		return "success";
	}
	
	@RequestMapping(value="/book",method=RequestMethod.POST)
	public String addBook(){
		System.out.println("添加了新的图书");
		return "success";
	}
	
	@RequestMapping(value="/book/{bid}", method=RequestMethod.PUT)
	public String updateBook(@PathVariable("bid")Integer bid){
		System.out.println("更新了"+bid+"号图书");
		return "success";
	}
}
HiddenHttpMethodFilter源码分析:
@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
     	//获取表单参数_method的值(delete\put)
        String paramValue = request.getParameter(this.methodParam);
     
     	//判断是否表单是一个post而且_method有值,若不是则放行
        if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
          	//转为大写的PUT、DELETE
            String method = paramValue.toUpperCase(Locale.ENGLISH);
          	//重写了新 new 的对象的request.getMethod()方法
            HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);

          	//wrapper.getMethod()===PUT;
            filterChain.doFilter(wrapper, response);
        }
        else {
            //直接放行
            filterChain.doFilter(request, response);
        }
    }

2. 映射请求参数

默认方式获取请求参数——直接在方法入参上写一个和请求参数名相同的变量。这个变量就来接收请求参数的值:

<a href="handle01?username=tomcat">handle01</a>
	@RequestMapping(value="handle01")
	public String handle02(String username){
		System.out.println("这个变量的值"+username);
		return "success";
	}

@RequestParam 获取请求参数;一旦标注了,则默认参数必须带;

	@RequestMapping(value="handle01")
	public String handle02(@RequestParam("username")String username){
		System.out.println("这个变量的值"+username);
		return "success";
	}

相当于javaweb的:

username = request.getParameter("user")

@RequestParam有三个参数:

  • value:指定要获取的参数的key
  • required:这个参数是否必须的,默认true
  • defaultValue:默认值。没带默认是null

@RequestHeader获取请求头中某个key的值
springmv获取方式:

@RequestMapping(value="handle01")
	public String handle02(@RequestHeader(value="User-Agent")String userAgent){
		System.out.println("请求头中浏览器的信息:"+userAgent);
		return "success";
	}

相当于javaweb的:

request.getHeader("User-Agent")

@RequestHeader有三个参数:

  • value:指定要获取的参数的key
  • required:这个参数是否必须的,默认true
  • defaultValue:默认值。没带默认是null

@CookieValue获取某个cookie的值

@RequestMapping(value="handle01")
	public String handle02(@CookieValue("JSESSIONID")String jid){
		System.out.println("cookie:"+jid);
		return "success";
	}

以前的操作获取某个cookie;

//获取到request中所有的Cookie
Cookie[] cookies = request.getCookies(); 

for(Cookie c:cookies){
	if(c.getName().equals("JSESSIONID")){ String cv = c.getValue(); } 
	}

@CookieValue有三个参数:

  • value:指定要获取的参数的key
  • required:这个参数是否必须的,默认true
  • defaultValue:默认值。没带默认是null

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

如果我们的请求参数是一个POJO,SpringMVC会自动的为这个POJO赋值

  • 将POJO中的每一个属性,从request参数中尝试获取出来,并封装即可
  • 还可以级联(属性的属性)封装
  • 请求参数的参数名和对象中的属性名一一对应就行
<form action="book" method="post">
	书名:<input type="text" name="bookName"/><br/>
	作者:<input type="text" name="author"/><br/>
	价格:<input type="text" name="price"/><br/>
	库存:<input type="text" name="stock"/><br/>
	销量:<input type="text" name="sales"/><br/>
	<hr/>
	省:<input type="text" name="address.province"/>
	市:<input type="text" name="address.city"/>
	街道:<input type="text" name="address.street"/><br/>
	<input type="submit"/>
</form>
public class Book {
	
	private String bookName;
	private String author;
	private Double price;
	private Integer stock;
	private Integer sales;
	private Address address;
	
	//一定有无参构造器
	
	public String getBookName() {
		return bookName;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	public Integer getStock() {
		return stock;
	}
	public void setStock(Integer stock) {
		this.stock = stock;
	}
	public Integer getSales() {
		return sales;
	}
	public void setSales(Integer sales) {
		this.sales = sales;
	}

	@Override
	public String toString() {
		return "Book [bookName=" + bookName + ", author=" + author + ", price="
				+ price + ", stock=" + stock + ", sales=" + sales
				+ ", address=" + address + "]";
	}
}

提交的数据可能有乱码:

  • 请求乱码:
    GET请求——改server.xml;在8080端口处URIEncoding="UTF-8"
    POST请求——在第一次获取请求参数之前设置request.setCharacterEncoding("UTF-8");;SpringMVC有一个filter
<!-- 配置字符编码的Filter;须注意:字符编码Filter一般都在其他Filter之前;因为Filter按照配置顺序进行拦截 -->
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<!-- encoding:指定解决POST请求乱码 -->
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<!-- forceEncoding:顺手解决响应乱码;
			response.setCharacterEncoding(this.encoding); -->
			<param-name>forceEncoding</param-name>	
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
  • 响应乱码:
    response.setContentType(“text/html;charset=utf-8”)

总结:使用SpringMVC前端控制器写完就直接写字符编码过滤器;Tomcat安装后,就在server.xml的8080处添加URIEncoding="UTF-8"

4. 使用 Servlet API 作为入参

MVC 的 Handler 方法可以接受哪些 ServletAPI 类型的参数:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • Locale:国际化有关的区域信息对象
  • InputStream:ServletInputStream inputStream = request.getInputStream();(字节流)
  • OutputStream:ServletOutputStream outputStream = response.getOutputStream();(字节流)
  • Reader:BufferedReader reader = request.getReader();(字符流)
  • Writer:PrintWriter writer = response.getWriter();(字符流)
@RequestMapping("/handle03")
	public String handle03(HttpSession session,
			HttpServletRequest request,HttpServletResponse response) throws IOException {
		request.setAttribute("reqParam", "我是请求域中的");
		session.setAttribute("sessionParam", "额我是Session域中的");
		
		return "success";
	}

5. 处理数据模型

概述

Spring MVC 提供了以下几种途径输出模型数据:

  • ModelAndView:处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
  • MapModel(一个接口)及ModelMap:入参为 org.springframework.ui.Modelorg.springframework.ui.ModelMapjava.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中
  • @SessionAttributes:将模型中的某个属性暂存到 HttpSession 中,以便多个请求之间可以共享这个属性
  • @ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中

具体

①SpringMVC 可以在方法处传入MapModelModelMap。在这些参数中保存(put()方法)的所有数据都会放在请求域Request中。最终在页面获取。

MapModelModelMap 最终都是BindingAwareModelMap在工作,即给BindingAwareModelMap保存的信息都被放在请求域中;
在这里插入图片描述

@RequestMapping(value="/handle01")
	public String handle01(Map<String,Object> map){
		map.put("key", "data");
		return "success1";
	}
	
	@RequestMapping(value="/handle02")
	public String handle02(Model model){
		model.addAttribute("key", "你好坏!");
		return "success1";
	}
	
	@RequestMapping(value="/handle03")
	public String handle03(ModelMap modelMap){
		modelMap.addAttribute("key", "你好!");
		return "success1";
	}

②方法的返回值可为ModelAndView类型,它既包含视图信息(页面地址)也包含模型数据(给页面带的数据),且数据放在请求域Request中;

	/**
	 * 返回值是ModelAndView;可以为页面携带数据
	 */
	@RequestMapping("/handle04")
	public ModelAndView handle04(){
		//之前的返回值我们就叫视图名;视图名视图解析器是会帮我们最终拼串得到页面的真实地址;
		//ModelAndView mv = new ModelAndView("success");
		ModelAndView mv = new ModelAndView();
		mv.setViewName("success");
		mv.addObject("msg", "你好哦!");
		return mv;
	}

③SpringMVC提供了可临时在Session域中保存数据的方式——使用注解@SessionAttributes(只能标在类上),但不推荐
例如:

@SessionAttributes(value={"msg1","msg2"},types={String.class}):
  • value属性表示给BindingAwareModelMapModelAndView中保存的数据,同时给session中放一份;value指定保存数据时要给session中放的数据的key

  • types属性只要保存的是这种类型的数据,给Session中也放一份

6. @RequestBody

  • @RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据);
  • GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。
  • 在后端的同一个接收方法里,@RequestBody@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值