文章目录
1 相应数据和结果视图
1.1 返回值分类
-
String:控制器方法返回字符串可以指定逻辑视图名,通过视图解析器解析为视图地址
-
void:默认是请求对应的jsp文件,也可以在方法中使用转发或者重定向跳转到指定页面。
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("testVoid。。。");
//默认是 user/testVoid.jsp
//转发
//request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
//重定向
//response.sendRedirect(request.getContextPath() + "/index.jsp");
//直接响应
//设置中文乱码
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("王二狗");
}
- ModelAndView:该对象有两个常用的方法,使用addObject方法以键值对的形式存数据,使用setViewName方法跳转页面。放回字符串的方法和无返回值的方法底层也调用的这个方法*
/**
* 返回ModeAndView,其他返回字符串的类底层也是调用的这个类
* @return
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
ModelAndView mv = new ModelAndView();
User user = new User();
user.setUsername("username");
user.setPassword("123");
user.setAge(12);
//把User对象存入到mv对象中,同时会把User对象存入到Request域中,因为ModelAndView底层就是用的Model
mv.addObject("user",user);
//跳转到那个页面
mv.setViewName("success");
return mv;
}
1.2 转发和重定向
- 转发:相当于
request.getRequestDispatcher("url").forward(request,response)
,控制器如果是使用String类型的返回值,默认就是请求转发。可以写成:
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
System.out.println("testForwardOrRedirect。。。");
//请求的转发,既可以转发到jsp,也可以转发到其他的控制器方法
return "forward:/WEB-INF/pages/success.jsp";
}
- 重定向:相当于
response.sendRedirect(url)
。不过如果重定向的是jsp页面,则jsp页面不能写在WEB-INF中,否则无法找到
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
System.out.println("testForwardOrRedirect。。。");
//重定向
return "redirect:/index.jsp";
}
1.3 ResponseBody注解响应json数据
作用:用于将控制器返回的对象,通过HttpMessageConverter接口转换为指定格式的数据(json,xml等),通过Response响应给客户端。
使用@ResponseBody注解需要导入三个依赖(实际上只需要一个即可,因为jackson-databind依赖另外两个包)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
jsp的使用json传数据:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
//jQuery需要的js文件,官网可下
<script src="js/jquery.min.js"></script>
<script>
//页面加载
$(function () {
$("#btn").click(function () {
//alert("hello btn");
//发送ajax请求
$.ajax({
//编写jsonge格式,设置属性和值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data:'{"username":"meteor","password":"123","age":"21"}',
dataType:"json",
type:"post",
success:function (data) {
//服务器端相应的json的数据,进行解析
alert(data.username + "的年龄:" + data.age);
}
});
});
});
</script>
</head>
<body>
<button id="btn">发送ajax请求</button>
</body>
</html>
控制器响应数据:
/**
* 模拟异步请求响应
*/
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
System.out.println("testAjax。。。");
//客户端发送ajax请求,传的是json字符串,后端把json字符串封装到user对象中
System.out.println(user);
//模拟查询数据库
user.setAge(22);
//响应
return user;
}
2 SpringMVC实现文件上传
文件上传的前提:
- form表单的enctype(表单请求正文的类型)取值必须是:
multipart/form-data
(默认值是:application/x-www-form-urlencoded
) - method属性取值必须是post
- 提供一个文件选择域
<input type="file" />
需要导入的jar包:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
2.1 传统方式文件上传
<h3>传统方式文件上传</h3>
<form action="user/fileUpload1" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload" /> <br>
<input type="submit" value="上传"/>
</form>
/**
* 传统方式:文件上传
* @return
*/
@RequestMapping("/fileUpload1")
public String fileUpload1(HttpServletRequest request) throws Exception{
//使用fileload组件完成文件上传
//1.上传的位置
String path = request.getSession().getServletContext().getRealPath("/upoads");
//2.判断该路径是否存在
File file = new File(path);
if(!file.exists()){
file.mkdir();
}
//3.解析request对象,获取到上传文档
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request
List<FileItem> items = upload.parseRequest(request);
//遍历
for(FileItem item : items){
//进行判断,当前item对象是否是上传文件项
if(item.isFormField()){
//说明是普通表单项
}else{
//说明是上传文件项
//获取上传文件名称
String filename= item.getName();
//把文件名称设置成唯一值
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
//完成文件上传
item.write(new File(path,filename));
//删除临时文件
item.delete();
}
}
System.out.println("文件上传成功,上传位置:" + path);
return "success";
}
2.2 springmvc实现文件上传
首先要配置文件解析器,注意id必须为multipartResolver
:
<!-- 配置文件解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 最大上传文件 KB-->
<property name="maxUploadSize" value="10485760"></property>
</bean>
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。
/**
* springmvc方式:文件上传
* @return
*/
@RequestMapping("/fileUpload2")
public String fileUpload2(HttpServletRequest request, MultipartFile upload) throws Exception{
//使用fileload组件完成文件上传
//1.上传的位置
String path = request.getSession().getServletContext().getRealPath("/upoads");
//2.判断该路径是否存在
File file = new File(path);
if(!file.exists()){
file.mkdir();
}
String filename = upload.getOriginalFilename();
//把文件名称设置成唯一值
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
//完成文件上传
upload.transferTo(new File(path,filename));
System.out.println("springmvc方式文件上传成功,上传位置:" + path);
return "success";
}
2.3 跨服务器实现文件上传
在实际开发中,为了提高运行效率,把服务器分为应用服务器和文件服务器,所以就有了跨服务器文件上传的需求。
实现跨服务器实现文件上传,首先要导入两个jar包:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
/**
* SpringMVC跨服务器方式的文件上传
*
* @param request
* @return
* @throws Exception
*/
@RequestMapping(value="/fileupload3")
public String fileupload3(MultipartFile upload) throws Exception {
System.out.println("SpringMVC跨服务器方式的文件上传...");
// 定义图片服务器的请求路径
String path = "http://localhost:9090/day02_springmvc5_02image/uploads/";
// 获取到上传文件的名称
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把文件的名称唯一化
filename = uuid+"_"+filename;
// 向图片服务器上传文件
// 创建客户端对象
Client client = Client.create();
// 连接图片服务器
WebResource webResource = client.resource(path+filename);
// 上传文件
webResource.put(upload.getBytes());
return "success";
}
一些问题:
- 上面的代码需要提前在文件服务器创建相应的路径,或者在代码中加入创建路径的功能。
- 如果文件写入不成功,可能是文件服务器的tomcat没有打开写入权限的原因,需要配置。
3 SpringMVC异常处理
系统的持久层、业务层、表现层的异常都是通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
自定义异常类:
public class SysException extends Exception{
/**
* 提示信息
*/
private String msg;
//----setter and getter
}
错误页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
错误信息:${errorMsg}
</body>
</html>
自定义异常处理器(需要实现HandlerExceptionResolver
接口):
/**
* 异常处理器
*/
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 处理异常的业务逻辑
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param e 前端控制器传来的异常
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
//获取到异常对象
SysException exception = null;
if(e instanceof SysException){
exception = (SysException) e;
}else{
exception = new SysException("系统正在维护");
}
//创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("errorMsg",exception.getMsg());
modelAndView.setViewName("error");
return modelAndView;
}
}
配置异常处理器:
<bean id="sysExceptionResolver" class="com.wxy.exception.SysExceptionResolver"></bean>
4 Spring的拦截器
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,但是只用于对处理器进行预处理和后处理,同时也支持“拦截器链”——一个拦截器放行后执行下一个拦截器或者处理器方法。
拦截器和过滤器的区别:
拦截器 | 过滤器 |
---|---|
是servler规范中的一部分,任何java web工程都可以使用 | 是springMVC框架自己的,只有使用了SpringMVC框架的工程才能用 |
在url-pattern中配置了/*之后,可以对所有要访问的资源拦截 | 它只会拦截访问的控制器方法,其他的是不会拦截的。 |
自定义拦截器,首先要实现HandlerInterceptor
接口:
/**
* 自定义拦截器
*/
public class myInterceptor1 implements HandlerInterceptor {
/**
* 处理器执行前执行
* @param request
* @param response
* @param handler
* @return true 放行,执行下一个拦截器,如果没有执行controller中的方法;false,不放行
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前处理方法1");
return true;
}
/**
* 处理器执行完执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("后处理方法1");
}
/**
* 页面加载结束执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("页面加载结束1");
}
}
配置拦截器:
<!-- 配置拦截器-->
<mvc:interceptors>
<!-- 配置具体的拦截器-->
<mvc:interceptor>
<!-- 要拦截的具体的方法-->
<mvc:mapping path="/user/*"/>
<!-- 不要拦截的方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<!-- 配置拦截器-->
<bean class="com.wxy.Interceptor.myInterceptor1"></bean>
</mvc:interceptor>
<!-- 如果要配置第二个拦截器-->
<!-- <mvc:interceptor>
<mvc:mapping path="/user/*"/>
<bean class="com.wxy.Interceptor.myInterceptor2"></bean>
</mvc:interceptor> -->
</mvc:interceptors>
当配置多个拦截器时的执行顺序: