简介
springmvc与struts2不同
- springmvc的入口是一个servlet即前端控制器,Servlet比过滤器快,而struts2入口是一个filter过滤器。
- springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
- Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面。Jsp视图解析器默认使用jstl。
运行速度:
Struts2是多例,请求来了以后,struts2创建多少个对象:ActionContext,valuestack,UserAction,ActionSuport,ModelDriven。userAction里面属性:User对象,userlist集合等
Springmvc是单列。
参数封装来分析:
Struts基于属性进行封装。
Springmvc基于方法封装。
参数绑定
如果使用Model则可以不使用ModelAndView对象,Model对象可以向页面传递数据,View对象则可以使用String返回值替代。不管是Model还是ModelAndView,其本质都是使用Request对象向jsp传递数据
@RequestMapping("/itemEdit")
public String queryItemById(HttpServletRequest request, Model model) {
// 从request中获取请求参数
String strId = request.getParameter("id");
Integer id = Integer.valueOf(strId);
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
// 把结果传递给页面
// ModelAndView modelAndView = new ModelAndView();
// 把商品数据放在模型中
// modelAndView.addObject("item", item);
// 设置逻辑视图
// modelAndView.setViewName("itemEdit");
// 把商品数据放在模型中
model.addAttribute("item", item);
return "itemEdit";
}
简单数据、pojo、包装pojo、数组、List类型
-
简单数据类型绑定:
@RequestMapping("/itemEdit") public String queryItemById(int id, ModelMap model) {
-
pojo类型绑定
要求:pojo对象中的属性名和表单中input的name属性一致。@RequestMapping("/updateItem") public String updateItem(Item item)
-
包装pojo类型绑定
要求:包装pojo对象中的属性名和表单中input的name属性一致。
包装对象定义如下:public class QueryVo { private Item item; set/get。。。 } @RequestMapping("/queryItem") public String queryItem(QueryVo queryVo) {
-
绑定数组
包装类型 绑定数组类型,可以使用两种方式,pojo的属性接收,和直接接收@RequestMapping("queryItem") public String queryItem(QueryVo queryVo, Integer[] ids) { System.out.println(queryVo.getIds().length); System.out.println(ids.length); return "success"; }
-
绑定list
注意:接收List类型的数据必须是pojo的属性,如果方法的形参为ArrayList类型无法正确接收到数据。
方法(QueryVo 里面List<Items> itemList<input type name=itemList[${s.index}].name />
自定义参数绑定
-
自定义converter
//Converter<S, T> //S:source,需要转换的源的类型 //T:target,需要转换的目标类型 public class DateConverter implements Converter<String, Date> { @Override public Date convert(String source) { try { // 把字符串转换为日期类型 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd HH:mm:ss"); Date date = simpleDateFormat.parse(source); return date; } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 如果转换异常则返回空 return null; } }
-
配置converter
在spring.xml中配置:
<!-- 配置注解驱动 --> <!-- 如果配置此标签,可以不用配置... --> <mvc:annotation-driven conversion-service="conversionService" /> <!-- 转换器配置 --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="cn.springmvc.converter.DateConverter" /> </set> </property> </bean>
乱码
在web.xml中加入:
<!-- 解决post乱码问题 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 设置编码参是UTF8 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
对于get请求中文参数出现乱码解决方法有两个:
修改tomcat配置文件添加编码与工程编码一致,如下:
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
另外一种方法对参数进行重新编码:
String userName new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码
controller方法返回值
- ModelAndView
controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。 -
void
-
使用request转发页面:
request.getRequestDispatcher("页面路径").forward(request, response); request.getRequestDispatcher("/WEB-INF/jsp/success.jsp").forward(request, response);
-
通过response页面重定向:
response.sendRedirect("url") response.sendRedirect("/springmvc-web2/itemEdit.action");
-
通过response指定响应结果,例如响应json数据:
response.getWriter().print("{\"abc\":123}");
-
-
返回字符串
-
指定逻辑视图名,通过视图解析器解析为物理视图地址。
//指定逻辑视图名,经过视图解析器解析为jsp物理路径:/WEB-INF/jsp/itemList.jsp return "itemList";
-
Redirect重定向
return "redirect:/itemEdit.action?itemId=" + item.getId(); // 重定向后浏览器地址栏变更为重定向的地址, // 重定向相当于执行了新的request和response,所以之前的请求参数都会丢失 // 如果要指定请求参数,需要在重定向的url后面添加 ?itemId=1 这样的请求参数
-
forward转发
return "forward:/itemEdit.action"; // 使用转发的方式实现。转发后浏览器地址栏还是原来的请求地址, // 转发并没有执行新的request和response,所以之前的请求参数都存在
-
异常处理器
-
自定义异常类
public class MyException extends Exception { // 异常信息 private String message; public MyException() { super(); } public MyException(String message) { super(); this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
-
自定义异常处理器
public class CustomHandleException implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) { // 定义异常信息 String msg; // 判断异常类型 if (exception instanceof MyException) { // 如果是自定义异常,读取异常信息 msg = exception.getMessage(); } else { // 如果是运行时异常,则取错误堆栈,从堆栈中获取异常信息 Writer out = new StringWriter(); PrintWriter s = new PrintWriter(out); exception.printStackTrace(s); msg = out.toString(); } // 把错误信息发给相关人员,邮件,短信等方式 // TODO // 返回错误页面,给用户友好页面显示错误信息 ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("msg", msg); modelAndView.setViewName("error"); return modelAndView; } }
-
配置
在springmvc.xml中添加:
<!-- 配置全局异常处理器 --> <bean id="customHandleException" class="cn.ssm.exception.CustomHandleException"/>
图片上传
-
配置上传解析器
在springmvc.xml中配置文件上传解析器
<!-- 文件上传,id必须设置为multipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置文件上传大小 --> <property name="maxUploadSize" value="5000000" /> </bean>
-
jsp
<!-- 上传图片是需要指定属性 enctype="multipart/form-data" --> <!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> --> <form id="itemForm"action="${pageContext.request.contextPath }/updateitem.action" method="post" enctype="multipart/form-data"> <td>商品图片</td> <td> <c:if test="${item.pic !=null}"> <img src="${pageContext.request.contextPath }/pi/${item.pic}" width=100 height=100/> <br/> </c:if> <input type="file" name="pictureFile"/> </td>
-
controller
@RequestMapping("updateItem") public String updateItemById(Item item,MultipartFile pictureFile) throws Exception { // 图片上传 // 设置图片名称,不能重复,可以使用uuid String picName = UUID.randomUUID().toString(); // 获取文件名 String oriName = pictureFile.getOriginalFilename(); // 获取图片后缀 String extName = oriName.substring(oriName.lastIndexOf(".")); // 开始上传 pictureFile.transferTo(new File("C:/upload/image/" + picName + extName)); // 设置图片名到商品中 item.setPic(picName + extName); // --------------------------------------------- // 更新商品 this.itemService.updateItemById(item); return "forward:/itemEdit.action"; }
ajax方式
-
页面ajax
发送请求,上传图片:图片被关联表单。提交表单:jquery.form.js<script type="text/javascript"> function submitImgSize1Upload(){ var option={ type:'POST', url:'${pageContext.request.contextPath }/upload/uploadPic.do', dataType:'text', data:{ fileName : 'imgSize1File' }, success:function(data){ //把json格式的字符串转换成json对象 var jsonObj = $.parseJSON(data); //返回服务器图片路径,把图片路径设置给img标签 $("#imgSize1ImgSrc").attr("src",jsonObj.fullPath); //数据库保存相对路径 $("#imgSize1").val(jsonObj.relativePath); } }; $("#itemForm").ajaxSubmit(option); } </script>
-
uploadController
使用jersy服务器进行跨服务器上传:@Controller @RequestMapping("/upload") public class UploadController { @RequestMapping("uploadPic") public void uploadPic(HttpServletRequest request,String fileName,PrintWriter out){ //把Request强转成多部件请求对象 MultipartHttpServletRequest mh = (MultipartHttpServletRequest) request; //根据文件名称获取文件对象 CommonsMultipartFile cm = (CommonsMultipartFile) mh.getFile(fileName); //获取文件上传流 byte[] fbytes = cm.getBytes(); //文件名称在服务器有可能重复? String newFileName=""; SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); newFileName = sdf.format(new Date()); Random r = new Random(); for(int i =0 ;i<3;i++){ newFileName=newFileName+r.nextInt(10); } //获取文件扩展名 String originalFilename = cm.getOriginalFilename(); String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); //创建jesy服务器,进行跨服务器上传 Client client = Client.create(); //把文件关联到远程服务器 WebResource resource = client.resource(Commons.PIC_HOST+"/upload/"+newFileName+suffix); //上传 resource.put(String.class, fbytes); //ajax回调函数需要会写写什么东西? //图片需要回显:需要图片完整路径 //数据库保存图片的相对路径. String fullPath = Commons.PIC_HOST+"/upload/"+newFileName+suffix; String relativePath="/upload/"+newFileName+suffix; //{"":"","":""} String result="{\"fullPath\":\""+fullPath+"\",\"relativePath\":\""+relativePath+"\"}"; out.print(result); } }
json数据交互
@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容(json数据)转换为java对象并绑定到Controller方法的参数上。
@ResponseBody注解用于将Controller的方法返回的对象,通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
restful风格
- 使用注解@RequestMapping("item/{id}")声明请求的url{xxx}叫做占位符,请求的URL可以是“item /1”或“item/2”
-
使用(@PathVariable() Integer id)获取url上的数据
/** \* 使用RESTful风格开发接口,实现根据id查询商品 \* @param id \* @return */ @RequestMapping("item/{id}") @ResponseBody public Item queryItemById(@PathVariable() Integer id) { Item item = this.itemService.queryItemById(id); return item; }
如果@RequestMapping中表示为"item/{id}",id和形参名称一致,@PathVariable不用指定名称。如果不一致,例如"item/{ItemId}"则需要指定名称@PathVariable("itemId")。
拦截器
总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用
-
定义拦截器
实现HandlerInterceptor接口,如下:
public class HandlerInterceptor1 implements HandlerInterceptor { // controller执行后且视图返回后调用此方法 // 这里可得到执行controller时的异常信息 // 这里可记录操作日志 @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("HandlerInterceptor1....afterCompletion"); } // controller执行后但未返回视图前调用此方法 // 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示 @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println("HandlerInterceptor1....postHandle"); } // Controller执行前调用此方法 // 返回true表示继续执行,返回false中止执行 // 这里可以加入登录校验、权限拦截等 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception { // 从request中获取session HttpSession session = request.getSession(); // 从session中获取username Object username = session.getAttribute("username"); // 判断username是否为null if (username != null) { // 如果不为空则放行 return true; } else { // 如果为空则跳转到登录页面 response.sendRedirect(request.getContextPath() + "/user/toLogin.action"); } return false; } }
-
配置拦截器
在springmvc.xml中配置拦截器
<!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 所有的请求都进入拦截器 --> <mvc:mapping path="/item/**" /> <!-- 配置具体的拦截器 --> <bean class="cn.ssm.interceptor.HandlerInterceptor1" /> </mvc:interceptor> </mvc:interceptors>
配置
无法处理css、js等静态资源,所以无法正常显示
-
解决方案:
在springmvc.xml中配置<!-- 解决静态资源无法被springMVC处理的问题 --> <mvc:default-servlet-handler />
-
修改web.xml,让所有以action结尾的请求都进入SpringMVC
<servlet-mapping> <servlet-name>boot-crm</servlet-name> <!-- 所有的请求都进入springMVC --> <url-pattern>*.action</url-pattern> </servlet-mapping>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。