JSON 知识:
注意: 请根据自己的 Spring 版本下载最新的 jar,否则有肯能会报错。 报错异常可以参考我这篇博客:解决方案
① 导入 jackson 的 jar
② 在 springMVC 的配置文件中开启 MVC 驱动,<mvc:annotation-driven />
③ 在处理 ajax 请求的方法上加上注解**@ResponseBody**
④ 将要转换为 json 且响应到客户端的数据,直接作为该方法的返回值返回
【index.jsp】
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<script type="text/javascript" src="${pageContext.servletContext.contextPath}/js/jquery-1.8.2.min.js"></script>
<script type="text/javascript" >
$(function () {
$('#btn').click(function () {
$.ajax({
url:"testJson",
type:"POST",
dataType:"json",
success:function (msg) {
for(var i in msg){
var emp = msg[i];
alert("id="+emp.id+",lastName="+emp.lastName+",departmentName="+emp.department.departmentName);
}
}
});
});
});
</script>
</head>
<body>
<a href="testJson">测试JSON</a>
</body>
</html>
【JsonControllerTest.json】**@ResponseBody : ** SpringMVC 对 JSON 的支持
@Controller
public class JsonControllerTest {
@Autowired
private EmployeeDao employeeDao;
@RequestMapping(value = "/testJson")
@ResponseBody
public Collection<Employee> testJson(){
Collection<Employee> emps = employeeDao.getAll();
return emps;
}
}
【index.jsp】
<html>
<head>
<title>$Title$</title>
<link
rel="stylesheet"
href="${pageContext.servletContext.contextPath}/css/index_like.css"
/>
<script
type="text/javascript"
src="${pageContext.servletContext.contextPath}/js/jquery-1.8.2.min.js"
></script>
<script type="text/javascript">
$(function () {
$("#btn").click(function () {
$.ajax({
url: "testJson",
type: "POST",
dataType: "json",
success: function (msg) {
/*
[
{"id":1001,"lastName":"E-AA","email":"aa@163.com","gender":1,"department":{"id":101,"departmentName":"D-AA"}},
{"id":1002,"lastName":"E-BB","email":"bb@163.com","gender":1,"department":{"id":102,"departmentName":"D-BB"}},
{"id":1003,"lastName":"E-CC","email":"cc@163.com","gender":0,"department":{"id":103,"departmentName":"D-CC"}},
{"id":1004,"lastName":"E-DD","email":"dd@163.com","gender":0,"department":{"id":104,"departmentName":"D-DD"}},
{"id":1005,"lastName":"E-EE","email":"ee@163.com","gender":1,"department":{"id":105,"departmentName":"D-EE"}}
]
*/
// 第一种实现方式
/*var tb = "<table>";
tb += "<tr><th>id</th><th>lastName</th><th>email</th><th>gender</th><th>departmentName</th></tr>"
for(var i in msg){
var emp = msg[i];
tb += "<tr><td>"+emp.id+"</td><td>"+emp.lastName+"</td><td>"+emp.email+"</td><td>"+emp.gender+"</td><td>"+emp.department.departmentName+"</td></tr>"
}
tb += "</table>"
$('body').append(tb);*/
//第二种实现方式
$("body").append("<table></table>");
$("table").append(
"<tr><th>id</th><th>lastName</th><th>email</th><th>gender</th><th>departmentName</th></tr>"
);
for (var i in msg) {
var emp = msg[i];
$("table").append(
"<tr><td>" +
emp.id +
"</td><td>" +
emp.lastName +
"</td><td>" +
emp.email +
"</td><td>" +
emp.gender +
"</td><td>" +
emp.department.departmentName +
"</td></tr>"
);
}
},
});
});
});
</script>
</head>
<body>
<a href="hello">测试</a>
<br />
<a href="testJson">测试JSON</a>
<br />
<input id="btn" type="button" value="测试ajax" />
</body>
</html>
测试:
HttpMessageConverter<T> 是 Spring3.0 新添加的一个接口, 负责将请求信息转换为一个对象(类型为 T), 将对象(类型为 T)输出为响应信息
package org.springframework.http;
import java.io.IOException;
import java.io.InputStream;
public interface HttpInputMessage extends HttpMessage {
InputStream getBody() throws IOException;
}
package org.springframework.http;
import java.io.IOException;
import java.io.OutputStream;
public interface HttpOutputMessage extends HttpMessage {
OutputStream getBody() throws IOException;
}
使用 HttpMessageConverter将请求信息转化并绑定到处理方法的入参中或将响应结果转为对应类型的响应信息, Spring 提供了两种途径:
方式一:图片名字由服务进行绑定
【index.jsp】
<body>
<a href="down">下载图片</a>
</body>
【TestUploadAndDownController.java】
@RequestMapping(value = "/down")
public ResponseEntity<byte[]> down(HttpSession session) throws Exception {
// 获取下载文件的路径
String realPath = session.getServletContext().getRealPath("img");
String finalPath = realPath + File.separator + "2.jpg";
InputStream is = new FileInputStream(finalPath);
// available():获取输入流所读取的文件的最大字节数
byte[] bt = new byte[is.available()];
is.read(bt);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition","attachment;filename=zzz.jpg");
// 设置响应状态
HttpStatus status = HttpStatus.OK;
ResponseEntity<byte[]> entity = new ResponseEntity<>(bt, headers, status);
return entity;
}
测试:
方式二: 图片有请求方式来获取
【index.jsp】
<body>
<a href="down/1">下载图片</a>
</body>
【TestUploadAndDownController.java】
@RequestMapping(value = "/down/{username}")
public ResponseEntity<byte[]> down(@PathVariable("username") String username, HttpSession session) throws Exception {
// 获取下载文件的路径
String realPath = session.getServletContext().getRealPath("img");
String finalPath = realPath + File.separator + username+".jpg";
InputStream is = new FileInputStream(finalPath);
byte[] bt = new byte[is.available()];
is.read(bt);
// 获取请求头
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition","attachment;filename="+username+".jpg");
// 设置响应状态
HttpStatus status = HttpStatus.OK;
ResponseEntity<byte[]> entity = new ResponseEntity<>(bt, headers, status);
return entity;
}
测试:
<form action="up" method="post" enctype="multipart/form-data">
头像:<input type="file" name="uploadFile"/>
描述:<input type="text" name="desc"/>
<input type="submit" value="上传"/>
</form>
【配置 spingmvc.xml】不配置上传则会报错
<!--
处理文件,将客户端上传的File文件,处理为MultipartFile
注意:文件解析器的bean中id必须设置为multipartResolver
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置文件解析的编码,注意:一定要和页面的pageEncoding保持一致 -->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设置最大上传文件大小 -->
<property name="maxUploadSize" value="88888888"></property>
</bean>
【TestUploadAndDownController.java】
方式一:
@RequestMapping(value = "/up" ,method = RequestMethod.POST)
public String up (String desc, MultipartFile uploadFile, HttpSession session) throws IOException {
// 获取上传文件的名称
String filename = uploadFile.getOriginalFilename();
String path = session.getServletContext().getRealPath("phone") + File.separator + filename;
// 获取输入流
InputStream is = uploadFile.getInputStream();
// 获取输出流
File file = new File(path);
OutputStream fos = new FileOutputStream(file);
byte[] bt = new byte[1024];
int len;
while((len = is.read(bt)) != -1){
fos.write(bt, 0, len);
}
is.close();
fos.close();
return "success";
}
注意:上传出现异常
类型 异常报告 消息 E:\IDEA\SpringMVC\SpringMVC_demo3\out\artifacts\SpringMVC_demo3_war_exploded\phone\1.jpg (系统找不到指定的路径。) java.io.FileNotFoundException: E:\IDEA\SpringMVC\SpringMVC_demo3\out\artifacts\SpringMVC_demo3_war_exploded\phone\1.jpg (系统找不到指定的路径。)
解决方法:(以为自己的为例子)E:\IDEA\SpringMVC\SpringMVC_demo3\out\artifacts\SpringMVC_demo3_war_exploded 这个目录下创建一个phone 文件就可解决问题
可以在代码中写入 System.out.prinln(path); 方便查看图片上传的位置
方式二:
@RequestMapping(value = "/up",method = RequestMethod.POST)
public String up (MultipartFile uploadFile, HttpSession session) throws IOException {
// 获取上传文件的名称
String filename = uploadFile.getOriginalFilename();
String finalFileName = UUID.randomUUID() + filename.substring(filename.lastIndexOf("."));
String path = session.getServletContext().getRealPath("phone") + File.separator + finalFileName;
File file = new File(path);
uploadFile.transferTo(file);
return "success";
}
【index.jsp】
<form action="up" method="post" enctype="multipart/form-data">
头像:<input type="file" name="uploadFile"/>
头像1:<input type="file" name="uploadFile"/>
头像2:<input type="file" name="uploadFile"/>
<input type="submit" value="上传"/>
</form>
【TestUploadAndDownController.java】
@RequestMapping(value = "/up",method = RequestMethod.POST)
public String ups(MultipartFile[] uploadFile, HttpSession session) throws IOException {
for(MultipartFile uploadFiles : uploadFile){
// 判断文件是否为空
if(! uploadFiles.isEmpty()){
String filename = uploadFiles.getOriginalFilename();
String finalFileName = UUID.randomUUID() + filename.substring(filename.lastIndexOf("."));
String path = session.getServletContext().getRealPath("phone") + File.separator + finalFileName;
File file = new File(path);
uploadFiles.transferTo(file);
}
}
return "success";
}
Spring MVC 也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的 功 能 , 自 定 义 的 拦 截 器 可 以 实 现 HandlerInterceptor 接 口 , 也 可 以 继 承 HandlerInterceptorAdapter 适配器类 。
代码示例:
【spingmvc.xml】中配置拦截器(3 中方式)
①(推荐使用):
<mvc:interceptors>
<!--默认拦截所有的请求-->
<bean class="com.oy.online.springmvc.interceptor.FirstInterceptor"></bean>
</mvc:interceptors>
②:
<mvc:interceptors>
<!--此方式要求拦截器类上必须加注解@Component -->
<ref bean="firstInterceptor"></ref>
</mvc:interceptors>
③:
<mvc:interceptors>
<!-- 设置自定义拦截方式 -->
<mvc:interceptor>
<bean class="com.oy.online.springmvc.interceptor.FirstInterceptor"/>
<!-- 拦截所有的请求,这个必须写在前面,也就是写在【不拦截】的上面 -->
<mvc:mapping path="/**" />
<!-- 但是排除下面这些,也就是不拦截请求 -->
<mvc:exclude-mapping path="/login.html" />
</mvc:interceptor>
</mvc:interceptors>
【index.jsp】
<body>
<a href="testInterceptor">测试拦截器</a>
</body>
【FirstInterceptor.java】
preHandle(): 中的 return 值 true 表示不拦截放行,反之 false 拦截
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("First:preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("First:postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("First:afterCompletion");
}
}
【TestInterceptorController.java】
@Controller
public class TestInterceptorController {
@RequestMapping(value = "/testInterceptor")
public String testInterceptor(){
return "success";
}
}
测试:
图解:
总结:
对一些特殊的异常进行处理,比如:
代码示例:
【index.jsp】
<body>
<a href="testException">异常测试</a>
</body>
【ExceptionControllerTest.java】
@RequestMapping(value = "/testException",method = RequestMethod.POST) // 不能是POST请求
public String testException(){
System.out.println("testDefaultHandlerExceptionResolver...");
return "success";
}
测试:
<!--异常处理-->
<bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>
【ExceptionControllerTest.java】
@RequestMapping(value = "/testSimpleMappingException")
public String testSimpleMappingException(){
System.out.println("testSimpleMappingException....");
String[] s = new String[10];
// s[i] 下标大于数组的长度
System.out.println(s[12]);
return "success";
}
测试:
【eeor.jsp】
<body>
<a href="#">操作异常,请稍后重试</a>
<br>
${requestScope.exception }
</body>
工作流程描述:
② 存在:
需要:通常情况下,类似于数据源,事务,整合其他框架都是放在 Spring 的配置文件中(而不是放在 SpringMVC 的配置文件中),实际上方入 Spring 配置文件对应的 IOC 容器中还有 Servlet 和 Dao。 不需要:都放在 SpringMVC 的配置文件中,也可以分多个 Spring 的配置文件,然后使用 import 节点导入其他的配置文件
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:bean.xml</param-value>
</context-param>
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--设置扫描组件的包-->
<context:component-scan base-package="com.oy.online.springmvc">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--<bean id="teacher" class="com.oy.online.springmvc.bean.Teacher"></bean>-->
</beans>
<!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.oy.online.springmvc.Controller"/>
<!-- 配置视图解析器 -->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
注意:在 Teanch 类中增加构造方法,启动服务器,查看构造器执行情况。若 Spring 的 IOC 容器 和 SpringMVC 的 IOC 容器扫描的包有重合的部分,就会导致有的 bean 会被创建 2 次。
解决:使 Spring 的 IOC 容器扫描的包和 SpringMVC 的 IOC 容器扫描的包没有重合的部分.使用 exclude-filter 和 include-filter 子节点来规定只能扫描的注解 。
【bean.xml】: <!– 不扫描@Controller 注解 –>
【Springmvc.xml】:<!– 扫描@Controller 注解 –>
<body>
<a href="testListener">监听器测试</a>
</body>
public class SpringListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
ServletContext servletContext = servletContextEvent.getServletContext();
servletContext.setAttribute("context", context);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
【ExceptionControllerTest.java】
@Controller
public class ExceptionControllerTest {
@RequestMapping()
public void testListener(HttpSession session){
// 获取spring所管理的teacher对象
ServletContext servletContext = session.getServletContext();
ApplicationContext context = (ApplicationContext) servletContext.getAttribute("context");
Teacher teacher = context.getBean("Teacher", Teacher.class);
System.out.println(teacher);
}
}
测试: