实验十一:Spring MVC的高级功能
一、实验目的
1.熟悉Spring MVC异常的统一处理
2.掌握自定义拦截器的使用
3.掌握文件上传和文件下载操作
二、实验内容
1.简单异常处理器、自定义异常处理器、异常处理注解、拦截器的配置实现
2.文件上传、文件下载应用
三、实验步骤
1.简单异常处理器、自定义异常处理器、异常处理注解、拦截器的配置实现
(1)简单异常处理器
① 创建ExceptionController.java类
在src\main\java文件夹中创建com\sun\controller文件夹,并创建ExceptionController类
package com.sun.controller;
导入相关包......
public class ExceptionController {
@RequestMapping("/showNullPointer")
public void showNullPointer(){
ArrayList<Object>list=null;
System.out.println(list.get(2));
}
@RequestMapping("/showIOException")
public void showIOException() throws IOException{
FileInputStream in=new FileInputStream("JavaWeb.xml");
}
@RequestMapping("/showArithmetic")
public void showArithmetic(){
int c=1/0;
}
}
② 配置spring-mvc.xml
在src\main\resources文件夹中创建spring-mvc.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/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
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.sun.controller"/>
<mvc:annotation-driven/>
<mvc:resources mapping="/js/**" location="/js/"/>
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.NullPointerException">
nullPointerExp.jsp
</prop>
<prop key="IOException">IOExp.jsp</prop>
</props>
</property>
<property name="defaultErrorView" value="defaultExp.jsp"></property>
<property name="exceptionAttribute" value="exp"></property>
</bean>
</beans>
③ 创建nullPointerExp.jsp
在src\main\webapp文件夹中创建nullPointerExp.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>空指针异常处理页面</title>
</head>
<body>
空指针异常处理页面----${exp}
</body>
</html>
④ 创建IOExp.jsp
在src\main\webapp文件夹中创建IOExp.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>IO异常处理页面</title>
</head>
<body>
IO异常处理页面-----${exp}
</body>
</html>
⑤ 创建defaultExp.jsp
在src\main\webapp文件夹中创建defaultExp.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>默认异常处理页面</title>
</head>
<body>
默认异常处理页面-----${exp}
</body>
</html>
运行结果:
启动项目后在浏览器输入http://localhost:8090/sy_ch11/showNullPointer
启动项目后在浏览器输入http://localhost:8090/sy_ch11/showIOException
启动项目后在浏览器输入http://localhost:8090/sy_ch11/showArithmetic
(2)自定义异常处理器
① 创建自定义异常类
在src\main\java文件夹中创建com\sun\exception文件夹,并创建自定义异常类
package com.sun.exception;
public class MyException extends Exception{
private String message;
public MyException(String message) {
super(message);
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
② 修改ExceptionController.java类
在ExceptionController.java类中添加
@RequestMapping("/addData")
public void addData() throws MyException {
throw new MyException("新增数据异常!");
}
③ 创建自定义异常处理器
在src\main\java\com\sun\controller文件夹下创建创建MyExceptionHandler类
package com.sun.controller;
导入相关包....
@Controller
public class MyExceptionHandler implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
String msg;
if (ex instanceof MyException) {
msg = ex.getMessage();
} else {
Writer out = new StringWriter();
PrintWriter s = new PrintWriter(out);
ex.printStackTrace(s);
String sysMsg = out.toString();
msg = "网络异常!";
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", msg);
modelAndView.setViewName("error.jsp");
return modelAndView;
}
}
④ 创建异常处理页面
在src\main\webapp文件夹下创建error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>异常处理页面</title>
</head>
<body>
${msg}
</body>
</html>
运行结果:
启动项目后在浏览器输入http://localhost:8090/sy_ch11/showNullPointer
启动项目后在浏览器输入http://localhost:8090/sy_ch11/addData
(3)异常处理注解
① 创建异常处理器
在src\main\java\com\sun\controller文件夹下创建ExceptionAdvice
package com.sun.controller;
导入相关包....
@Controller
public class ExceptionAdvice {
@ExceptionHandler(MyException.class)
public ModelAndView doMyException(MyException ex) throws IOException {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", ex.getMessage());
modelAndView.setViewName("error.jsp");
return modelAndView;
}
@ExceptionHandler(Exception.class)
public ModelAndView doOtherException(Exception ex) throws IOException {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "网络异常!");
modelAndView.setViewName("error.jsp");
return modelAndView;
}
}
运行结果:
启动项目后在浏览器输入http://localhost:8090/sy_ch11/showNullPointer
启动项目后在浏览器输入http://localhost:8090/sy_ch11/addData
(4)拦截器的配置实现
① 创建实体类
在src\main\java文件夹下创建com\sun\pojo文件夹,并创建User类
package com.sun.pojo;
public class User {
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private String username;
private String password;
}
② 创建控制器类
在src\main\java\com\sun\controller文件夹下创建创建控制器UserController类
package com.sun.controller;
导入相关包.....
@Controller
public class UserController {
@RequestMapping("/main")
public String toMainPage() {
return "main";
}
@RequestMapping("/tologin")
public String toLoginPage() {
return "login";
}
@RequestMapping("/orderinfo")
public String orderinfo() {
return "orderinfo";
}
@RequestMapping("/login")
public String login(User user, Model model, HttpSession session) {
String username = user.getUsername();
String password = user.getPassword();
if (username != null && username.equals("sunhaaonan") && password != null && password.equals("123456")) {
session.setAttribute("USER_SESSION", user);
return "main";
}
model.addAttribute("msg", "用户名或密码错误,请重新登录!");
return "login";
}
@RequestMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:tologin";
}
}
③ 创建拦截器
在src\main\java文件夹下创建com\sun\interceptor文件夹,并创建拦截器 LoginInterceptor
package com.sun.intercepto;
导入相关包.....
public class LoginInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String uri = request.getRequestURI();
if (uri.indexOf("/login") >= 0) {
return true;
}
HttpSession session = request.getSession();
if (session.getAttribute("USER_SESSION") != null) {
return true;
}
request.setAttribute("msg", "您还没有登录,请先登录!");
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
④ 配置spring-mvc.xml
在spring-mvc.xml文件中添加
<context:component-scan base-package="com.sun.controller"/>
<mvc:annotation-driven/>
<mvc:resources mapping="/js/**" location="/js/"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:interceptors>
<bean class="com.sun.interceptor.LoginInterceptor"/>
</mvc:interceptors>
⑤ 创建main.jsp
在src\main\webapp\WEB-INF文件夹下创建jsp文件夹,并创建main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>后台系统</title>
</head>
<body>
<li>您好:${ USER_SESSION.username }</li>
<li><a href="${ pageContext.request.contextPath }/logout">退出</a></li>
<li><a href="${ pageContext.request.contextPath }/orderinfo">订单信息</a></li>
</body>
</html>
⑥ 创建login.jsp
在src\main\webapp\WEB-INF\jsp文件夹下创建login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登录</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/login" method="POST">
<div>${msg}</div>
用户名:<input type="text" name="username"/><br/>
密 码:<input type="password" name="password"/><br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
⑦ 创建orderinfo.jsp
在src\main\webapp\WEB-INF\jsp文件夹下创建orderinfo.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>订单信息</title>
</head>
<body>
您好:${ USER_SESSION.username }
<a href="${ pageContext.request.contextPath }/logout">退出</a>
<table border="1" width="80%">
<tr align="center">
<td colspan="2">订单id:D001</td>
</tr>
<tr align="center">
<td>商品Id</td>
<td>商品名称</td>
</tr>
<tr align="center">
<td>P001</td>
<td>三文鱼</td>
</tr>
<tr align="center">
<td>P002</td>
<td>红牛</td>
</tr>
</table>
</body>
</html>
运行结果:
启动项目后在浏览器输入http://localhost:8090/sy_ch11/main
启动项目后在浏览器输入http://localhost:8090/sy_ch11/orderinfo
不填写任何信息点击“登录”:
登录后:
点击“订单信息”
点击“退出”:
2.文件上传、文件下载应用
(1)搭建文件上传和下载的环境
① 在项目的pom.xml中引入相关依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
② 配置spring-mvc.xml
<bean id="multipartResolver" class="org.springframework.
web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="2097152"/>
</bean>
(2)实现文件上传功能
① 文件存放准备
在webapp文件夹下创建名为files文件夹,用于存放上传成功的文件和上传成功的文件记录。上传成功的记录文件中的数据以JSON格式存放。在files文件夹中创建files.json记录文件
② 创建资源类
在src\main\java\com\sun\pojo文件夹中创建与file.json内容对应的资源类Resource
package com.sun.pojo;
public class Resource {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
public Resource(){}
public Resource(String name){
this.name=name;
}
}
③ 创建工具类
在src\mian\java文件夹中,创建文件夹com\sun\utils并创建工具类JSONFileUtils
package com.sun.utils;
import org.apache.commons.io.IOUtils;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class JSONFileUtils {
public static String readFile(String filepath) throws Exception {
FileInputStream fis = new FileInputStream(filepath);
return IOUtils.toString(fis);
}
public static void writeFile(String data, String filepath)
throws Exception { FileOutputStream fos = new FileOutputStream(filepath);
IOUtils.write(data, fos);
}
}
④ 创建控制类
在src\main\java\com\sun\controller文件夹下创建控制类FileController
package com.sun.controller;
导入相关包.....
@Controller
public class FileController {
@RequestMapping("/fileUpLoad")
public String fileLoad(MultipartFile[] files, HttpServletRequest request) throws Exception {
String path = request.getServletContext().getRealPath("/") + "files/";
ObjectMapper mapper = new ObjectMapper();
if (files != null && files.length > 0) {
for (MultipartFile file : files) {
String filename = file.getOriginalFilename();
ArrayList<Resource> list = new ArrayList<>();
String json = JSONFileUtils.readFile(path + "/files.json");
if (json.length() != 0) {
list = mapper.readValue(json,
new TypeReference<List<Resource>>() {
});
for (Resource resource : list) {
if (filename.equals(resource.getName())) {
String[] split = filename.split("\\.");
filename = split[0] + "(1)." + split[1];
}
}
}
String filePath = path + filename;
file.transferTo(new File(filePath));
list.add(new Resource(filename));
json = mapper.writeValueAsString(list);
JSONFileUtils.writeFile(json, path + "/files.json");
}
request.setAttribute("msg", "(上传成功)");
return "forward:fileload.jsp";
}
request.setAttribute("msg", "(上传失败)");
return "forward:fileload.jsp";
}
}
(3)实现获取文件列表功能
在控制类FileController中添加getFilesName()方法
@ResponseBody
@RequestMapping(value = "/getFilesName", produces = "text/html;charset=utf-8")
public String getFilesName(HttpServletRequest request, HttpServletResponse response) throws Exception {
String path = request.getServletContext().getRealPath("/") + "files/files.json";
String json = JSONFileUtils.readFile(path);
return json;
}
(4)编写文件上传和下载页面
在webapp文件夹下创建fileload.jsp文件作为文件上传和下载页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传和下载</title>
<script src="${ pageContext.request.contextPath }/js/jquery-3.6.0.js"
type="text/javascript"></script>
</head>
<body>
<table border="1">
<tr>
<td width="200" align="center">文件上传${msg}</td>
<td width="300" align="center">下载列表</td>
</tr>
<tr>
<td height="100">
<form action="${pageContext.request.contextPath}/fileload" method="post" enctype="multipart/form-data">
<input type="file" name="files" multiple="multiple"><br/>
<input type="reset" value="清空"/>
<input type="submit" value="提交"/>
</form>
</td>
<td id="files"></td>
</tr>
</table>
</body>
<script>
$(document).ready(function () {
var url = "${pageContext.request.contextPath }/getFilesName";
$.get(url, function (files) {
var files = eval('(' + files + ')');
for (var i = 0; i < files.length; i++) {
$("#files").append("<li><a href=${pageContext.request.contextPath }\\download?filename=" + files[i].name + ">" + files[i].name + "</a></li>");
}
})
})
</script>
</html>
运行结果:
启动项目后在浏览器输入http://localhost:8090/sy_ch11/fileload.jsp
单击“选择文件”按钮:
同时选择两个文件:
单击“打开”按钮:
单击“提交”按钮:
文件上传成功后查看项目files
双击打开files.json文件
(5)实现文件下载
① 对浏览器的编码方式进行设置
在控制类FileController中添加getFileName()方法
public String getFileName(HttpServletRequest request, String filename) throws Exception {
BASE64Encoder base64Encoder = new BASE64Encoder();
String agent = request.getHeader("User-Agent");
if (agent.contains("Firefox")) {
filename = "=?UTF-8?B?" + new String
(base64Encoder.encode(filename.getBytes("UTF-8"))) + "?=";
} else {
filename = URLEncoder.encode(filename, "UTF-8");
}
return filename;
}
② 新增下载文件方法
在控制类FileController中添加fileDownload()方法
@RequestMapping("/download")
public ResponseEntity<byte[]> fileDownload(HttpServletRequest request, String filename) throws Exception {
String path = request.getServletContext().getRealPath("/files/");
filename = new String(filename.getBytes("ISO-8859-1"), "UTF-8");
File file = new File(path + File.separator + filename);
HttpHeaders headers = new HttpHeaders();
filename = this.getFileName(request, filename);
headers.setContentDispositionFormData("attachment", filename);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
}
运行结果:
点击文件的超链接弹出对话框