Spring Mvc 学习笔记

浏览器进行request请求时 先有一个前端控制器处理 再到mvc.xml文件处理返回 再请求conterller 经过一系列的处理(验证、访问数据库等)返回到前端控制器处理返回的数据填充转到对应的视图链接中,然后再响应response到浏览器中 。。完成一个请求

Spring Mvc 学习笔记





配置映射器 
可以使用简单映射<!-- 简单url映射 --> 一次性映射多个
无论你访问的是/queryItems1.action 还是 /queryItems2.action 最终都映射到类ItemsController1 然后再访问itemsList


适配器 要求编写的Handler实现Controller或HttpRequestHandler接口(@Controller可以使用注解 扫描包)


视图解析器 


<!-- 配置Handler 如果请求的URL 为“上下文/queryItems.action”将会成功映射到ItemList1控制器。 -->
<bean id="ItemsController1" name="/queryItems_test.action" class="adongge.ssm.controller.ItemsController1"/> 
<!-- 配置另外一个Handler -->
<bean id="ItemsController2" class="adongge.ssm.controller.ItemsController2"/> 


注解型 使用controller标识 他是一个控制器 @Controller //RequestMapping实现对queryItems和url进行映射,一个方法对应一个url
@RequestMapping("/queryItems")
扫描一个包
<context:component-scan base-package="adongge.ssm.controller"></context:component-scan> 




窄化请求映射
在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理
@Controller
@RequestMapping("/item")
比如访问 商品列表 、/items/queryItems.action


//限制HTTP的请求方法 method可以设置范围 可以get 也可以 POST
@RequestMapping(value="/editItems",method={RequestMethod.POST,RequestMethod.GET})


Redirect重定向
//重定向到queryItem.action地址,request无法带过去
return "redirect:queryItem.action";
redirect方式相当于“response.sendRedirect()”
如果要传参数可以/item/queryItem.action后边加参数,如:/item/queryItem?...&…..


forward转发
return "forward:editItem.action";


Model/ModelMap
madel是一个接口,modelMap是一个接口实现
作用:将model数据填充到request域中


参数绑定
editItems(Modelmodel,@RequestParam(value="id",required=true,defaultValue="") Integer items_id)
@RequestParam里边指定request传入参数名称和形参进行绑定。
通过required属性指定参数是否必须要传入
通过defultValue可以设置默认值,如果id参数没有传入,将默认和形参绑定



自定义参数绑定(如日期 yyyy-MM-dd HH:mm:ss)
java类
public class CustomDateConverter implements Converter<String, Date> {
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.parse(source);
}
}
xml配置
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>


<!-- conversionService -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 转换器 -->
<property name="converters">
<list>
<bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
</list>
</property>
</bean>


<c:forEach items="${itemsList }" var="item" varStatus="status">
<td><input name="itemsList[${status.index }].name" value="${item.name }"></td>
<td><input name="itemsList[${status.index }].price" value="${item.price }"></td>
itemsList:对应包装pojo中的list类型的属性名
status.index:下标从0开始
name:对应了包装pojo中list类型的属性中的pojo属性名


在CustomValidationMessages.properties文件中定义值
//效验名称在1到30之间
//message是提示效验出错显示的信息
@Size(min=1,max=30,message="{items.name.length.error}")
private String name;


//非空效验
@NotNull(message="{items.createtime.isNUll}")


简单类型的回显 
//传入的id重新放到request域
model.addAttribute("id", id);
springmvc默认支持pojo数据回显,springmvc自动将形参中的pojo重新放回request域中,
//在需要效验的pojo前面添加@Validated,在需要效验的pojo后面加BindingResult bindingResult 接收效验的错误信息,两个参数固定一前一后,固定形参
//(value= {ValidGroup1.class}指定使用ValidGroup1分组的效验
public String editItemsSubmit(@ModelAttribute("items") @Validated(value= {ValidGroup1.class}) ItemsCustom itemsCustom, BindingResult bindingResult) {
model.addAttribute("allErrors", allErrors);//传递给前端页面
}


前端页面接收
<c:if test="${allErrors!=null }">
<c:forEach items="${allErrors }" var="error">
${error.defaultMessage }
</c:forEach>
</c:if>








<!-- 全局异常处理器  只要实现HandlerExceptionResolver接口就是全局异常处理器 只能一个类起作用-->
<bean class="cn.itcast.ssm.exception.CustomExceptionResolver"></bean>


public class CustomExceptionResolver implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse Response, Object arg2,
Exception ex) {
//解析异常类型
//如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示
if(ex instanceof CustomException) {
customException = (CustomException)ex;
}else {
//如果该异常类型是系统自定义的异常,构造一个自定义的异常类型(信息为未知错误)
customException = new CustomException("未知错误");
}
//错误信息
String message = customException.getMessage();
.....创建视图 ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", message);//将错误信息传到页面
modelAndView.setViewName("error");//指向错误页面

}
}


如果与业务功能相关的异常,建议在service中抛出(id不存在)
与业务功能无关的异常,建议在controller中抛出(商品名称过长)
if(items == null) {
throw new CustomException("修改的商品信息不存在");
}


MultipartFile items_pic//接收商品图片//原始名称
String originalFilename = items_pic.getOriginalFilename();
if(items_pic!=null && originalFilename!=null && originalFilename.length()>0 ) {
//储存图片的物理途径
String pic_path = "E:\\a\\";

//新图片名称
String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
//新图片
File newFile = new File(pic_path+newFileName);
//将内存中的数据 写入磁盘
items_pic.transferTo(newFile);
//将新图片名称写到itemsCustom中
itemsCustom.setPic(newFileName);
}




json  注意jar包的问题 jackson-.....
<input type="button" onclick="requestJson()" value="请求Json,输出的是Json"/>
function responseJson(){
$.ajax({
type:"post",
url:"${pageContext.request.contextPath }/requestJson.action",
contentType:"application/json;charset=utf-8",
data:'{"name":"测试商品","price":999}',
success:function(data){
alert(data);
}
});
@Controller
public class JsonTest {
//请求json串(商品信息) 输出json(商品信息)
//@RequestBody将请求的商品信息的json串转成itemsCustom对象
//@ResponseBody将itemsCustom转换成json输出
@RequestMapping("/requestJson")
public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom) {
//@ResponseBody将itemsCustom转换成json输出
return itemsCustom;
}




No converter found for return value of type: class cn.itcast.ssm.po.ItemsCustom


//查询商品信息
///itemsView/{id}里边的{id}表示将这个位置的参数传递到@PathVariable指定名称中
@RequestMapping("/itemsView/{id}")
public @ResponseBody ItemsCustom itemsView(@PathVariable("id") Integer id)throws Exception {
ItemsCustom itemsCustom = itemsService.findItemsById(id);
return itemsCustom;
}
配置web.xml<!--  springmvc前端控制器  rest配置 --> 
第二种:/,所以访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析使用此种方式可以实现 RESTful风格的url


<!-- 静态资源的解析 包括js,css,img 这样就可以访问-->
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/img/" mapping="/img/**"/>






<!--拦截器 -->
<mvc:interceptors>
<!--多个拦截器,顺序执行 -->
<mvc:interceptor>
<!-- /**表示所有url包括url子路径 -->
<mvc:mapping path="/**"/>
<bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1"></bean>
</mvc:interceptor>
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用


postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用


public class HandlerInterceptor1 implements HandlerInterceptor{
。。。。。
。。。。
/**
* 进入Handler方法之前执行
* 由于身份认证 授权 没有登录 就拦截
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取请求url
String url = request.getRequestURI();
//判断url是否为公开地址 (实际使用时将公开地址配置在配置文件中)
//这里的公开地址是登录提交的地址
if(url.indexOf("login.action")>=0) {
//如果进行登录提交, 放行
return true;
}

//判断session
HttpSession session = request.getSession();
//从get中获取身份信息
String username = (String) session.getAttribute("username");

if(username != null) {
//身份存在放行
return true;
}

//执行这里表示用户身份需要认证 跳转到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);

//return false 表示拦截 不向下执行
//return true 表示放行
return false;
}


}