01_Springmvc学习及SSM整合
2017-08-29 本文已影响98人
明天你好向前奔跑
1. ssm的整合
思路:mvc三层架构
1. dao:mybatis
1.1. mybatis的核心配置文件:sqlMapConfig.xml --配置Mapper映射文件的包名作为别名。
1.2. applicationContext_dao.xml配置数据源,sqlSessionFactory(mybatis的session工厂),
配置Mapper接口的basepackage(mybatis的动态代理开发,根据接口mybatis实现,我们只需要提供接口与mapper的sql配置即可)
1.3. 上面1.2相当于完成了spring与mybatis的整合
2. service : spring
2.1. applicationContext_service.xml:配置service层的注解扫描:
<context:component-scan base-package="com.itdream.ssm.service" />
2.2. applicationContext_tx.xml:spring的事务管理
3. web : springmvc
3.1. springmvc.xml :
1. 配置controller的注解扫描
2. <!--配置注解驱动,HttpMappingHandlerMapping与HttpMappingHandlerAdapter代替默认淘汰的映射器与适配器-->
<mvc:annotation-driven/>
3. 配置视图解析器,简化controller层,返回页面view的书写
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
4. web.xml配置servlet容器(tomcat)启动加载spring,并且配置springmvc的前端控制器
<!--spring的核心监听器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:resources/spring/applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--springmvc的前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:resources/spring/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
这里SpringMVC在拦截url请求时有三种方式:
1. /* 拦截所有,包括JSP
2. / 拦截所有,不包括JSP
3. *.action 只拦截以.action结尾的请求,不拦截静态资源等其他资源
如果使用了第二种拦截方式,但是又要放行静态资源如 js/jquery/css等,可以在springmvc.xml中进行配置:
<!--
配置静态资源映射,让静态资源不被拦截
location : 原资源文件的物理路径
mapping : 映射的虚拟路径
-->
<mvc:resources mapping="/js/**" location="/js/"/>
2. springmvc的使用
2.1 @RequestMapping
通过@RequestMapping注解可以定义不同的处理器映射规则。
1.URL路径映射(写在方法上,根据url映射到对应的方法),value的值是数组,可以将多个url映射,到同一个方法,用逗号分隔
@RequestMapping(value="item")或@RequestMapping("/item")
@RequestMapping("/item/itemList.action")
public ModelAndView findItemList() {
// 查询商品数据
List<Item> list = this.itemService.queryItemList();
// 创建ModelAndView,设置逻辑视图名
ModelAndView mv = new ModelAndView("itemList");
// 把商品数据放到模型中
mv.addObject("itemList", list);
return mv;
}
2. 写在类上,窄化路径
如
@RequestMapping("/item")
public class itemController {}
相当于将所有方法上的RequestMapping前加了/item的前缀,可以用它来抽取或统一路径的前缀
3. 对方法的限定
限定GET方法
@RequestMapping(method = RequestMethod.GET)
限定POST方法
@RequestMapping(method = RequestMethod.POST)
2.2 Controller方法的返回值
1. 返回ModelAndView
controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。
2. 返回String(官方推荐)
controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。数据使用Model model的model.addAttribbute(k,v)存储到request域
此外:返回String还支持重定向与请求转发,例如:
return "redirect:/itemList.action";
return "forward: /itemEdit.action?id="+id;
3. 返回void
在Controller方法形参上可以定义request和response,使用request或response指定响应结果:适用于ajax请求访问
2.3 springmvc解决post请求乱码问题
在web.xml中添加拦截器,拦截所有请求,将其携带参数转为UTF-8格式
<!--解决Post乱码问题-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--设置编码参数是UTF-8-->
<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请求的乱码问题:
1.png
2.4 解决返回Json数据乱码问题
<!-- 解决返回Json数据乱码问题 -->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!-- 顺序不能乱 -->
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
2.4 springmvc中的自定义参数转换器
由于日期数据有很多种格式,springmvc没办法把字符串转换成日期类型。所以需要自定义参数绑定
前端控制器接收到请求后,找到注解形式的处理器适配器,对RequestMapping标记的方法进行适配,
并对方法中的形参进行参数绑定。可以在springmvc处理器适配器上自定义转换器Converter进行参数绑定。
一般使用<mvc:annotation-driven/>注解驱动加载处理器适配器,可以在此标签上进行配置。
1. 编写自定义转换器Converter 实现 Converter<S,T>
//S:source,需要转换的源的类型
//T:target,需要转换的目标类型
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
if (StringUtils.isEmpty(s)) {
return null;
}
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return df.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
2. 在springmvc.xml中配置自定义Converter
<!--conversion-service:自定义转换器-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--转换器配置-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itdream.ssm.converter.DateConverter"/>
</set>
</property>
</bean>
第二种方式:(了解)
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer" ref="customBinder"></property>
</bean>
<!-- 自定义webBinder -->
<bean id="customBinder" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService" />
</bean>
<!-- 转换器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.springmvc.convert.DateConverter" />
</set>
</property>
</bean>
注意:此方法需要独立配置处理器映射器、适配器,
不再使用<mvc:annotation-driven/>
3. springmvc的进阶知识点
3.1 自定义异常处理器
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
2.png为了区别不同的异常,通常根据异常类型进行区分,这里我们创建一个自定义系统异常。
如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。
//自定义异常
public class CustomerException extends Exception {
public CustomerException(String message) {
super(message);
}
}
接下来自定义异常处理器:
/**
* 自定义异常处理器
* Created by Administrator on 2017/8/29.
*/
public class MyEceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {
ModelAndView mav = new ModelAndView();
//根据不同的异常定义友好提示信息
if (e instanceof CustomerException) {
mav.addObject("errorMsg", e.getMessage());
} else {
mav.addObject("errorMsg", "未知异常");
}
e.printStackTrace();
//发生异常后跳转的页面WEB-INF/jsp/error.jsp
mav.setViewName("error");
return mav;
}
}
最后,在springmvc.xml中配置该自定义异常处理器即可,那么以后碰到异常,前端控制器都会交给这个异常处理器处理:
<!--配置全局自定义异常处理器-->
<bean id="myEceptionResolver" class="com.itdream.ssm.exception.MyEceptionResolver"/>
3.2 springmvc实现图片上传
图片上传后需要保存到本地磁盘,配置tomcat的虚拟路径,在tomcat的config/server.xml中修改:
DocBase : 真实路径 path : 虚拟路径
<Context docBase="D:\upload\img" path="/img" reloadable="false"/>
我使用的idea也可以直接在ide工具配置:
选择+,extra source选择要映射的真实路径,右侧ApplicationContext填写虚拟路径
3.png
配置完后,还需要在server勾选:勾选这里后,idea也可以直接访问tomcat的首页了,否则不行
4.png
加入jar包:
6.png在springmvc.xml中配置 文件上传解析器:
<!--配置文件上传解析器,id必须设为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--配置上传文件的最大大小:50M:1*1024*1024*50-->
<property name="maxUploadSize" value="52428800"/>
</bean>
同时前端页面需要满足:enctype="multipart/form-data
并且,input标签type为file,name与controller接收的形参名称一致
Controller实现文件上传,将上传的图片文件保存到本地服务器,并将路径保存到数据库:
//提供参数MultipartFile,参数名与前端的name一致
@RequestMapping("/updateItem.action")
public String updateItem(Items item, MultipartFile pictureFile) throws IOException {
//获取文件原始名称
String originalFilename = pictureFile.getOriginalFilename();
//获取后缀名
String ext = FilenameUtils.getExtension(originalFilename);
//获取uuid随机文件名
String name = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
String filename = "/img/" + name + "." + ext;
//save to disk 上传保存到本地服务器
pictureFile.transferTo(new File("D:/upload/img/" + name + "." + ext));
//save to database 保存路径到数据库
item.setPic(filename);
itemsService.updateItems(item);
return "redirect:/item/list.action";
}
3.3 json数据交互
加入jar包:
7.png@RequestBody:
@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容(json数据)
转换为java对象并绑定到Controller方法的参数上。
@ResponseBody
@ResponseBody注解用于将Controller的方法返回的对象,通过springmvc提供的HttpMessageConverter接口
转换为指定格式的数据如:json,xml等,通过Response响应给客户端
@RequestMapping("/testAjaxJson")
public @ResponseBody
Items testAjaxJson(@RequestBody Items item, ModelMap model) {
System.out.println(item);
return item;
}
3.4 Restful开发
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
1.使用注解@RequestMapping("item/{id}")声明请求的url
{xxx}叫做占位符,请求的URL可以是“item /1”或“item/2”
2.使用(@PathVariable() Integer id)获取url上的数据
如果@RequestMapping中表示为"item/{id}",id和形参名称一致,@PathVariable不用指定名称。
如果不一致,例如"item/{ItemId}"则需要指定名称@PathVariable("itemId")。
/**
* Restful风格开发 这里的url访问路径使用restful1.action,使用PathVariable()可以接收到url中的id
*/
@RequestMapping("restful{id}.action")
public String restful(@PathVariable() Integer id,ModelMap model) {
Items item = itemsService.findItemsById(id);
model.addAttribute("item",item);
return "editItem";
}
3.5 springmvc的自定义拦截器
自定义拦截器实现HandlerIntercepter接口:进而实现它的三个方法
public class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("执行方法前1");
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("执行方法后1");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("渲染页面后1");
}
}
在springmvc.xml中配置自定义拦截器:
<!--自定义拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itdream.ssm.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itdream.ssm.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用