1.SpringMVC返回JSON
请求页面代码如下:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" scr="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){
$("testJson").click(function(){
var url=this.href;
var args={};
$.post(url,args,function(data){
for(var i=0;i<data.length;i++){
var id=data[i].id;
var lastName=data[i].lastName;
alert(id+":"+lastName);
}
});
return false;
});
});
</script>
</head>
<body>
<a href="emps">List All Employees</a>
<a href="testJson" id="testJson">Test Json</a>
</body>
</html>
对应的java处理方法:
@ResponseBody
@RequestMapping("/testJson")
public Collection<Employee> testJson() {
return employeeDao.getAll();
}
导入jar包
使用原理
HttpMessageConverter<T>
是Spring3.0新添加的一个接口,负责将请求信息转换为一个对象(类型为T),将对象(类型为T)输出为响应信息
HttpMessageConverter<T>
接口定义的方法:
–BooleancanRead(Class<?>clazz,MediaTypemediaType)
:指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为clazz类型的对象,同时指定支持MIME类型(text/html,applaiction/json等)
–BooleancanWrite(Class<?>clazz,MediaTypemediaType)
:指定转换器是否可将clazz类型的对象写到响应流中,响应流支持的媒体类型在MediaType中定义。
–LIst<MediaType>getSupportMediaTypes()
:该转换器支持的媒体类型。
–T read(Class<? extends T>clazz,HttpInputMessageinputMessage)
:将请求信息流转换为T类型的对象。
–void write(Tt,MediaTypecontnetType,HttpOutputMessgaeoutputMessage)
:将T类型的对象写到响应流中,同时指定相应的媒体类型为contentType。
public interface HttpInputMessage extends HttpMessage {
InputStream getBody() throws IOException;
}
public interface HttpOutputMessage extends HttpMessage {
OutputStream getBody() throws IOException;
}
类对应的实现类
SpringMVC中默认的实现类有哪些:
Spring提供了两种途径:
–使用@RequestBody/ @ResponseBody
对处理方法进行标注
–使用HttpEntity<T> /ResponseEntity<T>
作为处理方法的入参或返回值
当控制器处理方法使用到@RequestBody/@ResponseBody
或HttpEntity<T>/ResponseEntity<T>
时, Spring首先根据请求头或响应头的Accept属性选择匹配的HttpMessageConverter
,进而根据参数类型或泛型类型的过滤得到匹配的HttpMessageConverter
,若找不到可用的HttpMessageConverter
将报错
@RequestBody
和@ResponseBody
不需要成对出现
测试样例,页面代码如下:
<form action="testHttpMessageConverter" method="POST" enctype="multipart/form-data">
File:<input type="file" name="file">
Desc:<input type="text" name="desc">
<input type="submit" value="sumbit">
</form>
过滤代码如下:
@ResponseBody
@RequestMapping("/testHttpMessageConverter")
public String testHttpMessageConverter(@RequestBody String body) {
System.out.println(body);
return "helloworld!"+new Date();
}
测试代码2:
页面jsp代码如下:
<a href="testResponseEntity">Test ResponseEntity</a>
过滤代码如下:
@RequestMapping("/testResponseEntity")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException{
byte[] body=null;
ServletContext servletContext=session.getServletContext();
InputStream in=servletContext.getResourceAsStream("/files/abc.txt");
body=new byte[in.available()];
in.read(body);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition","attachment;filename=abc.txt");
HttpStatus statusCode=HttpStatus.OK;
ResponseEntity<byte[]> resopnse=new ResponseEntity<byte[]>(body,headers,statusCode);
return resopnse;
}
2.国际化
关于国际化:
1.在页面上能能够根据浏览器语言设置的情况对文本(不是内容),时间,数值进行本地化处理
2.可以在bean中获取国际化资源文件Locale对应的信息
3.可以通过超链接切换Locale,而不再依赖于浏览器的语言设置情况
解决:
1.使用JSTL的fmt标签
配置spring配置文件
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
<mvc:view-controller path="/i18n" view-name="i18n"/>
<mvc:view-controller path="/i18n2" view-name="i18n2"/>
配置国际化资源文件:
jsp页面配置
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<fmt:message key="i18n.user"></fmt:message>
<br>
<a href="i18n2">I18n2 PAGE</a>
</body>
</html>
2.在bean中注入ResourceBundleMessageSource的示例,使用其对应的getMessage方法即可
springmvc配置文件信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<context:component-scan base-package="com.atguigu.springmvc"></context:component-scan>
<mvc:default-servlet-handler/>
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!-- 配置 ConversionService -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="employeeConverter"/>
</set>
</property>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
<!--
<mvc:view-controller path="/i18n" view-name="i18n"/>
-->
<mvc:view-controller path="/i18n2" view-name="i18n2"/>
</beans>
配置拦截方法
@Autowired
private ResourceBundleMessageSource messageSource;
@RequestMapping("/i18n")
public String testI18n(Locale locale) {
String val =messageSource.getMessage("i18n.user", null,locale);
System.out.println(val);
return "i18n";
}
3.配置LocalResolver和LocaleChangeInterceptor
运行原理:
•AcceptHeaderLocaleResolver:根据HTTP请求头的Accept-Language参数确定本地化类型,如果没有显式定义本地化解析器,SpringMVC使用该解析器。
•CookieLocaleResolver:根据指定的Cookie值确定本地化类型
•SessionLocaleResolver:根据Session中特定的属性确定本地化类型
•LocaleChangeInterceptor:从请求参数中获取本次请求对应的本地化类型。
springmvc配置文件信息如下:
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
</bean>
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
jsp页面配置
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<fmt:message key="i18n.user"></fmt:message>
<br>
<a href="i18n2">I18n2 PAGE</a>
<br>
<a href="i18n?locale=zh_CH">中文</a>
<br>
<a href="i18n?locale=en_US">英文</a>
</body>
</html>
3.文件上传
Spring MVC为文件上传提供了直接的支持,这种支持是通过即插即用的MultipartResolver实现的。Spring用Jakarta CommonsFileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResovler
Spring MVC上下文中默认没有装配MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用Spring的文件上传功能,需现在上下文中配置MultipartResolver
开发步骤
1.导入jar包
2.配置spring文件
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>
3.编写目标方法
@RequestMapping("/testFileUpload")
public String testFileUpload(@RequestParam("desc")String desc,
@RequestParam("file") MultipartFile file) throws IOException {
System.out.println("desc:"+desc);
System.out.println("OriginalFilename:"+file.getOriginalFilename());
System.out.println("InputStream:"+file.getInputStream());
String path="E:/"+new Date().getTime()+file.getOriginalFilename();
File newFile=new File(path);
file.transferTo(newFile);
return "success";
}
4.编写jsp页面:
<form action="testConversionServiceConverer" method="POST">
Employee:<input type="text" name="employee">
<input type="submit" value="Submit">
</form>
4.自定义拦截器
自定义的拦截器必须实现HandlerInterceptor接口
–preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求request进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。可以做权限设置,或者日志和事务
–postHandle():这个方法在业务处理器处理完请求后,渲染视图之前调用。可以对请求域中的属性和视图进行修改。
–afterCompletion():这个方法在DispatcherServlet完全处理完请求后被调用(渲染视图之后),可以在该方法中进行一些资源清理的操作。
1.自定义拦截器类
public class FirstInterceptor implements HandlerInterceptor{
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("[FirstInterceptor] afterCompletion");
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
// TODO Auto-generated method stub
System.out.println("[FirstInterceptor] postHandle");
}
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
// TODO Auto-generated method stub
System.out.println("[FirstInterceptor] preHandle");
return true;
}
}
2.springMVC中配置拦截器
<mvc:interceptors>
<bean class="com.atguigu.springmvc.crud.interceptors.FirstInterceptor"></bean>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
3.运行结果如下:
[FirstInterceptor] preHandle
list
[FirstInterceptor] postHandle
[FirstInterceptor] afterCompletion
preHandle:该方法在目标方法之前被调用
若返回为true,则继续调用后续的拦截器和目标方法
若返回为false,则不会再调用后续的拦截器和目标方法
执行顺序如下图所示:
指定拦截器springmvc配置
<mvc:interceptors>
<bean class="com.atguigu.springmvc.crud.interceptors.FirstInterceptor"></bean>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
<!--配置拦截器(不)作用的路径 -->
<mvc:interceptor>
<mvc:mapping path="/emps"/>
<!-- <mvc:exclude-mapping path=""/> -->
<bean class="com.atguigu.springmvc.crud.interceptors.SecondInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
运行结果如下:
[FirstInterceptor] preHandle
[SecondInterceptor] preHandle
list
[SecondInterceptor] postHandle
[FirstInterceptor] postHandle
[SecondInterceptor] afterCompletion
[FirstInterceptor] afterCompletion
拦截器调用顺序
5.异常处理
Spring MVC通过HandlerExceptionResolver处理程序的异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常。
SpringMVC提供的HandlerExceptionResolver的实现类
DispatcherServlet默认装配的HandlerExceptionResolver:
–没有使用mvc:annotation-driven/配置:
–使用了mvc:annotation-driven/配置:
主要处理Handler中用@ExceptionHandler注解定义的方法。
实例配置过程:
测试handler代码:
@RequestMapping("/testExceptionHandlerExceptionResolver")
public String testExceptionHandlerExceptionResolver(@RequestParam("i") int i) {
System.out.println("result:"+(10/i));
return "success";
}
异常处理方法:
@ExceptionHandler(ArithmeticException.class)
public String handleArithmeticException(Exception ex){
System.out.println("出异常了"+ex);
return "error";
}
配置页面可获取异常:
@ExceptionHandler(ArithmeticException.class)
public ModelAndView handleArithmeticException(Exception ex){
System.out.println("出异常了"+ex);
ModelAndView mv=new ModelAndView("error");
mv.addObject("exception",ex);
return mv;
}
jsp页面获取信息如下:
${exception }
1.在@ExceptionHandler方法的入参中可以加入Exception类型的参数,该参数即对应发生的异常对象
2.在@ExceptionHandler方法的入参中不能传入Map,若希望把异常信息传到页面上,需要使用ModelAndView最为返回值
执行方法2:
自定义处理类来进行异常处理
@ControllerAdvice
public class ExceptionHandlerTest {
@ExceptionHandler(ArithmeticException.class)
public ModelAndView handleArithmeticException(Exception ex){
System.out.println("---出异常了"+ex);
ModelAndView mv=new ModelAndView("error");
mv.addObject("exception",ex);
return mv;
}
}
@ControllerAdvice如果在当前Handler中找不到@ExceptionHandler方法类处理当前方法出现的异常,则将去@ControllerAdvice标记的类中查找@Exception标记的方法来处理异常。
自定义异常类,进行异常处理
@ResponseStatus(value=HttpStatus.FORBIDDEN,reason="用户名和密码不匹配!")
public class UserNameNotMatchPasswordException extends RuntimeException{
private static final long serialVersionUID = 1L;
}
定义请求处理方法
@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i) {
if(i==13) {
throw new UserNameNotMatchPasswordException();
}
System.out.println("testResponseStatusExceptionResolver....");
return "success";
}
运行结果如下:
使用异常方法
@ResponseStatus(reason="测试",value=HttpStatus.NOT_FOUND)
@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i) {
if(i==13) {
throw new UserNameNotMatchPasswordException();
}
System.out.println("testResponseStatusExceptionResolver....");
return "success";
}
测试结果如下:
DefaultHandlerExceptionResolver
对一些特殊的异常进行处理,比
如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException等。
jsp配置如下:
<a href="testDefaultHandlerExceptionResolver">Test DefaultHandlerExceptionResolver</a>
拦截代码如下:
@RequestMapping(value="/testDefaultHandlerExceptionResolver",method=RequestMethod.POST)
public String testDefaultHandlerExceptionResolver() {
System.out.println("testDefaultHandlerExceptionResolver");
return "success";
}
SimpleMappingExceptionResolver
如果希望对所有异常进行统一处理,可以使用SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常
jsp代码如下:
<a href="testSimpleMappingExceptionResolver?i=2">Test SimpleMappingExceptionResolver</a>
springMVC配置信息如下:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>
6.Spring整合SpringMVC
1.需要进行Spring整合SpringMVC吗?
1)需要:通常情况下,类似于数据源、事务、整合其他框架都是放在Spring的配置文件中(而不是放在SpringMVC的配置文件中),实际上放入Spring配置文件对应的IOC容器中的还有Service和Dao.
2)不需要,都放在SpringMVC的配置文件,也可以分成多个Spring的配置文件,然后使用import节点导入其他的配置文件
问题:若Spring的IOC容器和SpringMVC的IOC容器扫描的包有重合的部分,就会导致bean被创建2次。
使用exclude-filter和include-filter子节点来规定只能扫描的注解
1.使Spring的IOC容器扫描的包和SpringMVC的IOC扫描的包没有重合的部分。
2.还是否需要再加入Spring的IOC容器?
3.是否需要在web.xml文件中配置启动Spring IOC容器的ContextLoaderListener?
配置样例,web.xml中的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
</web-app>
springmvc.xml中的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<context:component-scan base-package="com.atguigu.springmvc" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<mvc:default-servlet-handler/>
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
beans.xml的文档配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<context:component-scan base-package="com.atguigu.springmvc" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<mvc:default-servlet-handler/>
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
SpringMVC的IOC容器中的bean可以用来引用Spring IOC容器中的bean,反之Spring IOC容器中的bean却不能来引用SpringMVC IOC容器中的bean。
多个Spring IOC容器之间可以设置为父子关系,以实现良好的解耦。
Spring MVC WEB层容器可作为“业务层”Spring容器的子容器:即WEB层容器可以引用业务层容器的Bean,而业务层容器却访问不到WEB层容器的Bean。
7.SpringMVC对比Struts2
•①. Spring MVC的入口是Servlet,而Struts2是Filter
•②. Spring MVC会稍微比Struts2快些. Spring MVC是基于方法设计,而Sturts2是基于类,每次发一次请求都会实例一个Action.
•③. Spring MVC使用更加简洁,开发效率Spring MVC确实比struts2高:支持JSR303,处理ajax的请求更方便
•④. Struts2的OGNL表达式使页面的开发效率相比Spring MVC更高些.