SpringMVC
第一章 自定义类型转换器
1.1 请求参数错误
客户端请求的参数是一个日期,在服务器端接收的时候,服务器无法识别该数据是日期,会出现400的错误
<form action="/paramsDate.do">
<input type="date" name="date">
<br>
<input type="submit">
</form>
@RequestMapping("paramsDate")
public ModelAndView paramsDate(Date date, ModelAndView modelAndView){
System.out.println("date = " + date);
return modelAndView;
}
1.2 自定义数据类型转换器
- 自定义类型转换器,实现接口Converter
- 泛型S,转换之前的数据类型
- 泛型T,转换之后的数据类型
public class MyStringDateConvert implements Converter<String, Date> {
@Override
public Date convert(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = sdf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
- 配置springmvc.xml
<mvc:annotation-driven conversion-service="conversionService"/>
<!--配置类型转换器-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.atguigu.convert.MyStringDateConvert" id="dateConvert"/>
</set>
</property>
</bean>
第二章 Controller类的方法返回值
1.1 返回字符串类型
返回字符串(直接返回逻辑视图名,数据使用Model和ModelMap封装)
- ModelAndView = model + view(逻辑视图名)
- 现在直接将逻辑视图名以字符串形式return(文件名)
- Model接口方法 addAttribute(String key,Object value)存储键值对,将被存储到request域中
/**
* 返回字符串,返回视图逻辑名,文件名
* Model接口封装数据
* 键值对存储request域对象
*/
@RequestMapping("gotoResultString")
public String gotoResultString(Model model){
System.out.println(model.getClass());
Date date = new Date();
model.addAttribute("nowDate",date);
return "index";
}
- ModelMap封装数据,方法addAttribute(String key,Object value)存储键值对,将被存储到request域中
@RequestMapping("gotoResultStringModelMap")
public String gotoResultStringModelMap(ModelMap modelMap){
Date date = new Date();
modelMap.addAttribute("nowDate",date);
return "index";
}
1.2 方法无返回值
- request对象实现转发
/**
* 直接使用request对象转发
*/
@RequestMapping("gotoResultRequest")
public void gotoResultRequestDispatcher(ModelMap modelMap, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/gotoResultStringModelMap.action").forward(request,response);
}
- response对象实现重定向
/**
* 直接使用response对象重定向
*/
@RequestMapping("gotoResultResponseSendRedirect")
public void gotoResultResponseSendRedirect(ModelMap modelMap, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendRedirect(request.getContextPath()+"/gotoResultStringModelMap.action");
}
- 重定向和转发的字符串写法
/**
* 直接使用response对象重定向
*/
@RequestMapping("gotoResultResponseSendRedirect")
public String gotoResultResponseSendRedirect(ModelMap modelMap, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//response.sendRedirect(request.getContextPath()+"/default/gotoResultStringModelMap.action");
return "redirect:/gotoResultStringModelMap.action";
}
/**
* 直接使用request对象转发
*/
@RequestMapping("gotoResultRequest")
public String gotoResultRequestDispatcher(ModelMap modelMap, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//request.getRequestDispatcher("/default/gotoResultStringModelMap.action").forward(request,response);
return "forward:/gotoResultStringModelMap.action";
}
第三章 RestFul风格URL
1.1 RestFul概念
RESTFul就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次。
REST:Representational State Transfer,表现层资源状态转移。
- 定位:互联网软件架构风格
- 倡导者:Roy Thomas Fielding
- 文献:Roy Thomas Fielding的博士论文
1.2 功能还是资源
传统的软件系统仅在本地工作,但随着项目规模的扩大和复杂化,不但整个项目会拓展为分布式架构,很多功能也会通过网络访问第三方接口来实现。在通过网络访问一个功能的情况下,我们不能轻易假设网络状况文档可靠。所以当一个请求发出后没有接收到对方的回应,那我们该如何判定本次操作成功与否?
下面以保存操作为例来说明一下针对功能和针对资源进行操作的区别:
- 针对功能设计系统
保存一个 Employee 对象,没有接收到返回结果,判定操作失败,再保存一次。但是其实在服务器端保存操作已经成功了,只是返回结果在网络传输过程中丢失了。而第二次的补救行为则保存了重复、冗余但 id 不同的数据,这对整个系统数据来说是一种破坏。 - 针对资源设计系统
针对 id 为 1000 的资源执行操作,服务器端会判断指定 id 的资源是否存在。如果不存在,则执行保存操作新建数据;如果存在,则执行更新操作。所以这个操作不论执行几次,对系统的影响都是一样的。在网络状态不可靠的情况下可以多次重试,不会破坏系统数据。
1.3 RestFul规范要求
传统方式操作资源
操作啥(原来url)?操作谁(传入的参数)
url中先定义动作,然后传递的参数表明这个动作操作的是哪个对象(数据)
先定位动作,然后定位对象
http://localhost:8080/springmvc02/user/queryUserById.action?id=1
查询
http://localhost:8080/springmvc02/user/saveUser.action
新增
http://localhost:8080/springmvc02/user/updateUser.action
更新
http://localhost:8080/springmvc02/user/deleteUserById.action?id=1
删除
使用RESTful操作资源
先定义对象
http://localhost:8080/springmvc02/user/1
(操作的对象) 查询,GET
http://localhost:8080/springmvc02/user
新增,POST
http://localhost:8080/springmvc02/user
更新,PUT
http://localhost:8080/springmvc02/user/1
删除,DELETE
REST 风格主张在项目设计、开发过程中,具体的操作符合 HTTP 协议定义的请求方式的语义。
操作 | 请求方式 |
---|---|
查询操作 | GET |
保存操作 | POST |
删除操作 | DELETE |
更新操作 | PUT |
1.4 RestFul优势
安全
使用问号键值对的方式给服务器传递数据太明显,容易被人利用来对系统进行破坏。使用 REST 风格携带数据不再需要明显的暴露数据的名称。
风格统一
URL 地址整体格式统一,从前到后始终都使用斜杠划分各个内容部分,用简单一致的格式表达语义。
简洁,优雅
过去做增删改查操作需要设计4个不同的URL,现在一个就够了。
1.5 HiddentHttpMethodFilter
由于浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0之后添加了一个过滤器HiddentHttpMethodFilter,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT 与DELETE请求.
<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>
@RequestMapping(method = RequestMethod.DELETE)
public void restDelete(){
System.out.println("Rest==Delete");
}
@RequestMapping(method = RequestMethod.PUT)
public void restPut(){
System.out.println("Rest==Put");
}
@RequestMapping(method = RequestMethod.POST)
public void restPost(){
System.out.println("Rest==Post");
}
@RequestMapping(method = RequestMethod.GET)
public void restGet(){
System.out.println("Rest==Get Request");
}
隐藏表单的name属性值,固定为_method
<a href="/restFul.do">Rest Get</a>
<form action="/restFul.do" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit">
</form>
<hr>
<form action="/restFul.do" method="post">
<input type="hidden" value="DELETE" name="_method">
<input type="submit">
</form>
<hr>
<form action="/restFul.do" method="post">
<input type="hidden" value="post" name="_method">
<input type="submit">
</form>
1.6 请求参数获取@PathVariable注解
超链接中添加单个参数:
<a href="/restFul/1.do">Rest Get</a>
@RequestMapping(method = RequestMethod.GET)
public void restGet(Integer id){
System.out.println("Rest==Get Request::"+id);
}
在方法restGet中是无法获取到参数id,需要使用注解@PathVariable,标明获取请求地址中的参数
@RequestMapping(value = "{id}",method = RequestMethod.GET)
public void restGet(@PathVariable("id") Integer id){
System.out.println("Rest==Get Request::"+id);
}
超链接中添加多个参数
<a href="/restFul/1/emp/true.do">Rest Get</a>
@RequestMapping(value = "{id}/{name}/{bool}",method = RequestMethod.GET)
public void restGetMore(@PathVariable("id") Integer id,@PathVariable("name") String name,@PathVariable("bool") Boolean bool){
System.out.println("Rest==Get Request::"+id +"::"+name+"::"+bool);
}