1.处理JSON
- @RequestBody和@ResposeBody
- @RequestBody
- 用来将请求报文转换为方法入参中的某个类型的对象
- 该注解只能添加到方法的入参前面
- 例如:将上传文件的流转换为方法入参中的一个字符串类型
- 表单
- @RequestBody
<
form
action
=
"
${pageContext.request.contextPath }
/testRequestBody"
method
=
"post"
enctype
=
"multipart/form-data"
>
描述:
<
input
type
=
"text"
name
=
"desp"
><
br
>
文件:
<
input
type
=
"file"
name
=
"wj"
><
br
>
<
input
type
=
"submit"
>
</
form
>
- 测试方法
@RequestMapping
(
"/testRequestBody"
)
public
String testRequestBody(
@RequestBody
String
body
){
System.
out
.println(
"请求报文中的信息是:"
+
body
);
return
"success"
;
}
这里如果是要显示保文信息就不用写
<
bean
id
=
"multipartResolver"
class
=
"org.springframework.web.multipart.commons.CommonsMultipartResolver"
>
设置字符集
<
property
name
=
"defaultEncoding"
value
=
"UTF-8"
></
property
>
设置文件的大小
<
property
name
=
"maxUploadSize"
value
=
"102400"
></
property
>
</
bean
>
- 也可以通过在方法的入参中传入HttpEntity<T>对象来实现类似的功能
- @ResposeBody
- 用来将Handler的方法的返回值以某种格式响应给前端
- 该注解可以添加到类上,也可以添加到方法上
- 如果添加到类上,Handler中的所有方法的返回值将直接响应给页面
@ResponseBody
//如果该注解添加到类上,
类中所有的方法的返回值
将直接响应给浏览器
@Controller
public
class
SpringMVCHandler {
- 如果添加到方法上,只有添加了该注解的方法的返回值会直接响应給页面
@ResponseBody
@RequestMapping
(
"/testResponseBody"
)
public
String testResponseBody(){
System.
out
.println(
"测试ResponseBody"
);
return
"success"
;
//当Handler的方法上添加了@ResponseBody注解之后返回值将直接响应给浏览器
JSP页面显示的是success
}
@ResponseBody
@RequestMapping
(
"/testResponseBody2"
)
public
String testResponseBody2(){
System.
out
.println(
"测试ResponseBody2"
);
return
"page"
;
//当Handler的方法上添加了@ResponseBody注解之后返回值将直接响应给浏览器
}
- 也可以通过将方法的返回值设置为ResponseEntity<T>来实现类似的功能
- 实现文件下载的功能
//实现文件下载的效果
@RequestMapping
(
"/testResponseEntity"
)
public
ResponseEntity<
byte
[]> testResponseEntity(HttpSession
session
)
throws
IOException{
//获取ServletContext对象
ServletContext
servletContext
=
session
.getServletContext();
//获取输入流
InputStream
is
=
servletContext
.getResourceAsStream(
"/download/meinv.jpg"
);
//创建byte数组
byte
[]
body
=
new
byte
[
is
.available()];
//将流读到数组中
is
.read(
body
);
//设置响应头
HttpHeaders
headers
=
new
HttpHeaders();
//告诉浏览器如果处理文件
headers
.add(
"Content-Disposition"
,
"attachment; filename=mn.jpg"
);
//设置
Http
的状态码为OK
HttpStatus
statusCode
= HttpStatus.
OK
;
//创建ResponseEntity
ResponseEntity<
byte
[]>
responseBody
=
new
ResponseEntity<
byte
[]>(
body
,
headers
,
statusCode
);
return
responseBody
;
}
- 实现文件上传功能
//文件上传
@RequestMapping("/testFileUpload")
public String testFileUpload(@RequestParam("desp") String desp ,
@RequestParam("wj") MultipartFile file , HttpSession session) throws IllegalStateException, IOException{
System.out.println("文件的描述性信息是:"+desp);
//获取文件名
String fileName = file.getOriginalFilename();
//获取文件的类型
String contentType = file.getContentType();
//获取文件的大小
long size = file.getSize();
System.out.println("文件名是:"+fileName);
System.out.println("文件的类型是:"+contentType);
System.out.println("文件的大小是:"+size+"字节");
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取upload目录在服务器端的真实路径
String realPath = servletContext.getRealPath("/upload");
//判断服务端是否有upload目录,如果没人,让它自动创建
File upload = new File(realPath);
if(!upload.exists()){
//创建该目录
upload.mkdirs();
}
//将文件上传到upload目录中
file.transferTo(new File(realPath+"/"+fileName));
return "success";
}
在springmvc.xml中需要配置以下
<
bean
id
=
"multipartResolver"
class
=
"org.springframework.web.multipart.commons.CommonsMultipartResolver"
>
<!-- //设置字符集 -->
<
property
name
=
"defaultEncoding"
value
=
"UTF-8"
></
property
>
<!-- 设置文件的大小 -->
<
property
name
=
"maxUploadSize"
value
=
"102400"
></
property
>
</
bean
>
- 处理JSON
- 导入以下jar包
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
- 发送一个Ajax请求并在处理请求的方法上添加@RequestBody注解
- 发送Ajax请求
<
button
id
=
"btn"
>
Test JSON
</
button
><
br
>
$(
function
(){
//给按钮绑定单击事件
$(
"#btn"
).click(
function
(){
//发送Ajax请求
//设置请求地址
var
url =
"${pageContext.request.contextPath }/testJSON"
$.post(url,
function
(data){
for
(
var
i = 0; i < data.length; i++){
alert(data[i].id+
"-"
+data[i].username);
}
});
});
});
- 处理请求
@ResponseBody
@RequestMapping
(
"/testJSON"
)
public
List<User> testJSON(){
System.
out
.println(
"通过发送Ajax请求处理JSON数据"
);
//创建一个List<User>
List<User>
list
=
new
ArrayList<>();
//向list中添加User对象
return
list
;
}
- 能实现上述功能是通过HttpMessageConverter<T>接口的具体实现类来实现的
2.国际化
- SpringMVC通过LocaleResolver解析器获取本地化信息,默认使用的解析器是AcceptHeaderLocaleResolver,这时发请求时会自动获取浏览器中的Accept-Language的属性值来实现国际化
- 实现国际化需要在SpringMVC的配置文件中配置国际化资源文件
<!-- 设置国际化资源文件 -->
<
bean
id
=
"messageSource"
class
=
"org.springframework.context.support.ResourceBundleMessageSource"
>
<!-- 设置国际化资源文件的基础名 -->
<
property
name
=
"basename"
value
=
"i18n"
></
property
>
</
bean
>
- 我们可以通过超链接的形式来实现中英文的切换
- 1)在SPringMVC的配置文件中配置SessionLocaleResolver解析器和LocaleChangeInterceptor拦截器
<!-- 配置SessionLocaleResolver -->
<
bean
id
=
"localeResolver"
class
=
"org.springframework.web.servlet.i18n.SessionLocaleResolver"
></
bean
>
<!-- 配置LocaleChangeInterceptor -->
<!-- 拦截器额执行顺序由配置的先后顺序决定 -->
<
mvc:interceptors
>
<
bean
class
=
"org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
>
<!-- 通过paramName属性设置超链接中传入的语言及国家信息的请求参数 -->
<
property
name
=
"paramName"
value
=
"
language
"
></
property
>
</
bean
>
</
mvc:interceptors
>
- 2)前端的超链接发送请求时需要携带一个请求参数,参数的默认的名字是locale,我们可以在LocaleChangeIntercepto中设置这个参数名
<
a
href
=
"
${pageContext.request.contextPath }
/testCutomerI18N?
language
=zh_CN"
>
中文
</
a
>
|
<
a
href
=
"
${pageContext.request.contextPath }
/testCutomerI18N?
language
=en_US"
>
ENGLISH
</
a
>
<!-- 设置不经过Handler的方法直接响应的页面 -->
<mvc:view-controller path="/testCutomerI18N" view-name="success"/>
- 通过1)和2)的设置之后,当我们点击超链接时,会将语言及国家的信息设置到session域中,以后在发送请求会直接从session域中获取语言及国家的信息,以此来实现国际化的操作
3.文件的上传
- 1)需要导入以下jar包
commons-fileupload-
1.3
.1.
jar
commons-io-2.5.
jar
- 2)在SpringMVC的配置文件中配置CommonsMultipartResovler解析器
<!-- 配置CommonsMultipartResovler -->
<
bean
id
=
"multipartResolver"
class
=
"org.springframework.web.multipart.commons.CommonsMultipartResolver"
>
<!-- 设置字符集 -->
<
property
name
=
"defaultEncoding"
value
=
"UTF-8"
></
property
>
<!-- 设置文件的大小 -->
<
property
name
=
"maxUploadSize"
value
=
"102400"
></
property
>
</
bean
>
- 3)上传文件的表单
<
form
action
=
"
${pageContext.request.contextPath }
/testFileUpload"
method
=
"post"
enctype
=
"multipart/form-data"
>
描述:
<
input
type
=
"text"
name
=
"desp"
><
br
>
文件:
<
input
type
=
"file"
name
=
"wj"
><
br
>
<
input
type
=
"submit"
>
</
form
>
- 4)处理文件上传的方法,该方法中需要传入一个MultipartFile类型的一个参数
@RequestMapping
(
"/testFileUpload"
)
public
String testFileUpload(
@RequestParam
(
"desp"
) String
desp
,
@RequestParam
(
"wj"
)
MultipartFile
file
, HttpSession
session
)
throws
IllegalStateException, IOException{
System.
out
.println(
"文件的描述性信息是:"
+
desp
);
//获取文件名
String
fileName
=
file
.getOriginalFilename();
//获取文件的类型
String
contentType
=
file
.getContentType();
//获取文件的大小
long
size
=
file
.getSize();
System.
out
.println(
"文件名是:"
+
fileName
);
System.
out
.println(
"文件的类型是:"
+
contentType
);
System.
out
.println(
"文件的大小是:"
+
size
+
"字节"
);
//获取ServletContext对象
ServletContext
servletContext
=
session
.getServletContext();
//获取upload目录在服务器端的真实路径
String
realPath
=
servletContext
.getRealPath(
"/upload"
);
//判断服务端是否有upload目录,如果没人,让它自动创建
File
upload
=
new
File(
realPath
);
if
(!
upload
.exists()){
//创建该目录
upload
.mkdirs();
}
//将文件上传到upload目录中
file
.transferTo(
new
File(
realPath
+
"/"
+
fileName
));
return
"success"
;
}
4.拦截器
- 自定义拦截器需要实现HandlerInterceptor接口
public
class
FirstInterceptor
implements
HandlerInterceptor {
/**
* 在调用目标方法之前执行
*
* 可以用来设置权限、日志、事务
*/
@Override
public
boolean
preHandle(HttpServletRequest
request
, HttpServletResponse
response
, Object
handler
)
throws
Exception {
System.
out
.println(
"FirstInterceptor的preHandle方法被调用"
);
return
true
;
}
/**
* 调用目标之后渲染视图之前执行
*
* 可以修改ModelAndView中模型数据及视图
*/
@Override
public
void
postHandle(HttpServletRequest
request
, HttpServletResponse
response
, Object
handler
,
ModelAndView
modelAndView
)
throws
Exception {
System.
out
.println(
"FirstInterceptor的postHandle方法被调用"
);
}
/**
* 渲染视图之后执行
*
* 可以用来释放资源
*/
@Override
public
void
afterCompletion(HttpServletRequest
request
, HttpServletResponse
response
, Object
handler
, Exception
ex
)
throws
Exception {
System.
out
.println(
"FirstInterceptor的afterCompletion方法被调用"
);
}
}
- 在SpringMVC中配置拦截器
<!-- 配置LocaleChangeInterceptor -->
<!-- 拦截器额执行顺序由配置的先后顺序决定 -->
<
mvc:interceptors
>
<
bean
class
=
"org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
>
<!-- 通过paramName属性设置超链接中传入的语言及国家信息的请求参数 -->
<
property
name
=
"paramName"
value
=
"language"
></
property
>
</
bean
>
<!-- 通过以下这种方式配置的拦截器会拦截所有的请求 -->
<
bean
class
=
"com.atguigu.springmvc.interceptor.FirstInterceptor"
></
bean
>
<!-- 也可以通过以下方式配置拦截器,通过这种方式可以配置拦截和不拦截那些请求 -->
<
mvc:interceptor
>
<!-- 设置拦截的请求 -->
<
mvc:mapping
path
=
"/testInterceptor"
/>
<!-- 设置不拦截那些请求 -->
<!-- <mvc:exclude-mapping path=""/> -->
<
bean
class
=
"com.atguigu.springmvc.interceptor.SecondInterceptor"
></
bean
>
</
mvc:interceptor
>
</
mvc:interceptors
>
- 具体多个拦截器的执行顺序请参照源码
5.异常处理
- Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常
- Spring MVC 提供的 HandlerExceptionResolver的实现类(打红色方框的)
- @ExceptionHandler注解
- 通过该注解标识一个处理异常的方法
@ExceptionHandler
(value=ArithmeticException.
class
)
//定义一个处理异常的方法
public
String resoveException(Exception
e
){
System.
out
.println(
"异常信息是:"
+
e
);
return
"error"
;
}
//异常匹配的优先级:
根据继承关系优先匹配
@ExceptionHandler
(value=RuntimeException.
class
)
//定义一个处理异常的方法
public
String resoveException2(Exception
e
){
System.
out
.println(
"[异常信息是]:"
+
e
);
return
"error"
;
}
@ExceptionHandler
(value=Exception.
class
)
//定义一个处理异常的方法
public
String resoveException3(Exception
e
){
System.
out
.println(
"【异常信息是】:"
+
e
);
return
"error"
;
}
- 在方法上添加了@ExceptionHandler注解之后,该方法只能处理当前Handler的方法执行时出现的异常,如果想定义一个全局的处理异常的方法,我们可以使用@ControllerAdvice注解标识一个处理异常的类
@ControllerAdvice
//
如果当前Handler中没有处理异常的方法,会去标识了@ControllerAdvice注解的类中去寻找处理异常的方法
public
class
ResolveExceptionClass {
//定义一个处理异常的方法
@ExceptionHandler
(value=Exception.
class
)
public
String resoveException3(Exception
e
){
System.
out
.println(
"{异常信息是}:"
+
e
);
return
"error"
;
}
}
实例:
JSP:
<
h2
>
出错信息
</
h2
>
${requestScope.exception }
类中
:
package
exception;
import
org.springframework.web.bind.annotation.ControllerAdvice;
import
org.springframework.web.bind.annotation.ExceptionHandler;
import
org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public
class
ResolveExceptionClass {
//定义一个处理异常的方法
@ExceptionHandler
(value=Exception.
class
)
public
ModelAndView
resoveException3(Exception
e
){
System.
out
.println(
"{异常信息是}:"
+
e
);
ModelAndView
mv
=
new
ModelAndView(
"error"
);
mv
.addObject(
"exception"
,
e
);
mv
.setViewName(
"error"
);
return
mv
;
}
}
异常对象不能通过
Map
集合方式传递给成功页面,
可以通过ModelAndView将异常对象传递给成功页面上
- @ResponseStatus
- 通过该注解可以标识一个异常类,当出现该异常时会去指定的异常页面
@ResponseStatus
(value=
HttpStatus.
UNAUTHORIZED
,reason=
"滚犊子!你没有此权限!!!"
)
public
class
UnAuthorizedException
extends
RuntimeException {
/**
*
*/
private
static
final
long
serialVersionUID
= 1L;
}
- 测试方法
@RequestMapping
(
"/testResponseStatus"
)
public
String testResponseStatus(
@RequestParam
(
"username"
) String
username
){
if
(!
"superAdmin"
.equals(
username
)){
//抛出没有权限的异常
throw
new
UnAuthorizedException();
}
return
"success"
;
}