一、SSM项目整合
1、搭建一个mave项目,并使用mave中的web组件
2、导入架包到pom.xml,并完善相应的基本文件夹
<dependencies>
<!--spring核心容器包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring切面包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
<!--aop联盟包-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!--springJDBC包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring事务控制包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring orm 映射依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.5</version>
</dependency>
<!--Apache Commons日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--log4j2 日志-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.14.0</version>
<scope>test</scope>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!--spring test测试支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.5</version>
<scope>test</scope>
</dependency>
<!--junit5单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<!--springMVC支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
<!--jsp 和Servlet 可选-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!--json依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<!--mybatis 核心jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!--spring mybatis整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
</dependencies>
4、在数据库中创建 user表,字段名为 uid,uname,password,并创建实体类User.java
package com.xiaohui.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer uid;
private String uname;
private String password;
}
5、在resource目录下创建log4j2.xml文件,并进行配置
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
6、创建并配置jdbc.properties文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root
7、创建并配置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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--扫描controller-->
<context:component-scan base-package="com.xiaohui.controller"></context:component-scan>
<!--配置三大组件 处理器映射器,处理器适配器,视图解析器-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--指定路径的前缀和后缀-->
<!-- <property name="prefix" value="/WEB-INF/view/"></property>-->
<!-- <property name="suffix" value=".jsp"></property>-->
</bean>
<!--配置静态资源放行-->
<!--<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>-->
<!--<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>-->
<!--<mvc:resources mapping="/img/**" location="/img/"></mvc:resources>-->
<!--<mvc:resources mapping="/static/**" location="/static/"></mvc:resources>-->
</beans>
8、创建并配置applicationContext.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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--加载properties配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--包扫描,仅仅扫描service层-->
<context:component-scan base-package="com.xiaohui.service"></context:component-scan>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
</bean>
<!--配置sqlSessionFactory-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"></property>
<!--实体类别名包扫描-->
<property name="typeAliasesPackage" value="com.xiaohui.pojo"></property>
</bean>
<!--sqlSession >>> *** Mapper -->
<!--MapperScanner mapper扫描仪 生辰所有的Mapper对象并放入容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sessionFactory"></property>
<!--扫描所有的Mapper接口和映射文件-->
<property name="basePackage" value="com.xiaohui.mapper"></property>
</bean>
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
9、在webapp》WEB-INF》web.xml文件中进行配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--向ServletContext中添加spring核心配置文件的位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--spring核心容器配置-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置前端控制器DispatcherServlet-->
<servlet>
<servlet-name>dispatcherServlet</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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--CharcterEncodingFilter-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
10、编写业务代码
UserController.java
package com.xiaohui.controller;
import com.xiaohui.pojo.User;
import com.xiaohui.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("login.do")
public String login(String uname, String password) {
String view = "";
User user = userService.findUser(uname, password);
if (null != user) {
view = "/success.jsp";
} else {
view = "/fail.jsp";
}
return view;
}
@ResponseBody
@RequestMapping("findAllUser.do")
public List<User> findAllUser(){
return userService.findAllUser();
}
}
UserServiceImpl.java
package com.xiaohui.service.impl;
import com.xiaohui.mapper.UserMapper;
import com.xiaohui.pojo.User;
import com.xiaohui.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findUser(String uname, String password) {
return userMapper.findUser(uname,password);
}
@Override
public List<User> findAllUser() {
return userMapper.findAllUser();
}
}
UserMapper.java
package com.xiaohui.mapper;
import com.xiaohui.pojo.User;
import java.util.List;
public interface UserMapper {
User findUser(String uname, String password);
List<User> findAllUser();
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaohui.mapper.UserMapper">
<!--User findUser(String uname, String password);-->
<select id="findUser" resultType="user">
select
*
from
user
where
uname = #{param1}
and
password = ${param2}
</select>
<!--List<User> findAllUser();-->
<select id="findAllUser" resultType="user">
select * from user
</select>
</mapper>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="login.do" method="post">
<input type="text" name="uname">
<input type="password" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
登录成功
</body>
</html>
fail.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
登录失败
</body>
</html>
二、作用域传参
- PageContext对象
- 作用域范围:当前jsp页面内有效
- request对象
- 作用域范围:一次请求内。
- 作用: 解决了一次请求内的资源的数据共享问题
- session对象
- 作用域范围:一次会话内有效。
- 说明:浏览器不关闭,并且后台的session不失效,在任意请求中都可以获取到同一个session对象。
- 作用:解决了一个用户不同请求的数据共享问题。
- application(ServletContext)对象
- 作用域范围:整个项目内有效。
- 特点:一个项目只有一个,在服务器启动的时候即完成初始化创建无论如何获取都是同一个项目。
- 作用:解决了不同用户的数据共享问题。
1、传统方式传递数据
package com.xiaohui.controller;
import com.xiaohui.pojo.User;
import com.xiaohui.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
@Controller
public class ScopeController {
@Autowired
private UserService userService;
/*定义一个处理单元,向三个域放入数据*/
@RequestMapping("setData")
public String setData(HttpServletRequest request, HttpSession session){
//向三个域中放入数据
List<User> userList = userService.findAllUser();
request.setAttribute("message","requestMessage");
request.setAttribute("users",userList);
session.setAttribute("message","sessionMessage");
session.setAttribute("users",userList);
ServletContext application = request.getServletContext();
application.setAttribute("message","applicationMessage");
application.setAttribute("users",userList);
return "/showDataPage.jsp";
}
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--域中的数据--%>
requestScope:message:${requestScope.message},users:${requestScope.users} <br/>
sessionScope:message:${sessionScope.message},users:${sessionScope.users} <br/>
applicationScope:message:${applicationScope.message},users:${applicationScope.users} <br/>
</body>
</html>
2、使用Model传递数据
model对象addAttribute
主要是对请求域传递数据进行了API上的封装
降低了controller和servlet之间的耦合度
重定向下,没法使用model传递域中的数据
model中的字符串类型的键值对信息会转换为请求参数,转发到目标组件
@RequestMapping("setData2")
public String setData2(Model model){
//向三个域中放入数据
List<User> userList = userService.findAllUser();
model.addAttribute("message","requestMessage");
model.addAttribute("users",userList);
return "/showDataPage.jsp";
}
showDataPage.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--域中的数据--%>
requestScope:message:${requestScope.message},users:${requestScope.users} <br/>
sessionScope:message:${sessionScope.message},users:${sessionScope.users} <br/>
applicationScope:message:${applicationScope.message},users:${applicationScope.users} <br/>
<%--请求参数--%>
requestParam:${param.message}
</body>
</html>
3、使用ModelAndView传递数据
/*
* ModelAndView
* Model数据
* View 视图
* */
@RequestMapping("setData3")
public ModelAndView setData3(){
ModelAndView modelAndView = new ModelAndView();
Map<String, Object> model = modelAndView.getModel();
//向三个域中放入数据
List<User> userList = userService.findAllUser();
model.put("message","requestMessage");
model.put("users",userList);
modelAndView.setViewName("forward:/showDataPage.jsp");
return modelAndView;
}
二、文件上传
随着我们互联网的发展,我们的用户从直接访问网站获取信息。变为希望将自己本地的资源发送给服务器,让服务器提供给其他人使用或者查看。还有部分的用户希望可以将本地的资源上传服务器存储起来,然后再其他的电脑中可以通过访问网站来获取上传的资源,这样用户就可以打破空间的局限性,再任何时候只要有网有电脑就可以对自己的资源进行操作,比如:云存储,云编辑
1如何在页面中显示一个按钮
用户可以点击该按钮后选择本地要上传的文件在页面中使用input标签,type值设置为”file”即可
2确定上传请求的发送方式
上传成功后的响应结果在当前页面显示,使用ajax请求来完成资源的发送
3上传请求的请求数据及其数据格式
请求数据:
上传的文件本身普通数据:用户名,Id,密码等,建议上传功能中不携带除上传资源以外的数据
数据格式:
传统的请求中,请求数据是以键值对的格式来发送给后台服务器的,但是在上传请求中,没有任何一个键可以描述上次的数据,因为数据本身是非常大的键就相当于一个变量,我们使用一个变量存储一个10g的电影显然是不可能 的。在上传请求中,将请求数据以二进制流的方式发送给服务器。
4在ajax中如何发送二进制流数据给服务器
① 创建FormData的对象,将请求数据存储到该对象中发送
② 将processData属性的值设置为false,告诉浏览器发送对象请求数据
③ 将contentType属性的值设置为false,设置请求数据的类型为二进制类型。
④ 正常发送ajax即可
5上传成功后后台服务器应该响应什么结果给浏览器
并且浏览器如何处理后台服务器处理完成后,响应一个json对象给浏览器,示例格式如下:
{ state:true,msg:“服务器繁忙”,url:”上传成功的资源的请求地址”}
6 文件上传依赖的jar
<!--文件上传依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
7、配置文件上传组件
springmvc.xml
<!--文件上传解析组件
id必须为multipartResolver
springmvc默认使用该id找该组件
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
8、准备用户表
前端代码 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
</head>
<script type="text/javascript">
$(function () {
$("#uploadFile").click(function () {
//获取要上传的文件
var photoFile = $("#photo")[0].files[0];
if (photoFile == undefined) {
alert("您还未选择文件");
return;
}
//将文件装入FromData对象中
var formData = new FormData();
formData.append("multipartFile", photoFile);
//ajax向后台发送文件
$.ajax({
type: "post",
data: formData,
url: "fileUpload.do",
processData: false,
contentType: false,
success: function (result) {
//接收后台响应的信息
console.log(result);
//图片回显
}
})
})
})
</script>
<body>
<div style="text-align:center">
<h2>用户注册界面</h2>
<form action="addPlayer" method="get">
<p>账号:<input type="text" name="name"/></p>
<p>密码:<input type="password" name="password"/></p>
<p>昵称:<input type="text" name="nickname"/></p>
<p>
头像:<br/><input id="photo" type="file" name="photo"/>
<a id="uploadFile" href="javascript:void(0)">立即上传</a>
</p>
<p><input type="submit" name="注册"/></p>
</form>
</div>
</body>
</html>
FileUploadController.java
package com.xiaohui.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
@Controller
public class FileUploadController {
@ResponseBody
@RequestMapping("fileUpload.do")
public String fileUpload(MultipartFile multipartFile, HttpServletRequest request) throws IOException {
//指定文件存储目录为当前项目部署环境下的upload目录
String realPath = request.getServletContext().getRealPath("/upload");
System.out.println(realPath);
File file = new File(realPath);
//判断目录存不存在,不存在则创建
if(!file.exists()){
file.mkdirs();
}
//获取文件名
String originalFilename = multipartFile.getOriginalFilename();
//文件存储位置
File outFile = new File(file,originalFilename);
//文件保存
multipartFile.transferTo(outFile);
return "Ok";
}
}
在SpringMVC中配置静态资源放行
<mvc:resources mapping="/upload/**" location="/upload/"></mvc:resources>
- 文件上传中的几个问题
- 1 中文文件名编码问题:
- 已经通过过滤器解决
- 2 文件位置存储问题
- 放在当前项目下,作为静态资源,这样可以通过URL访问
- 1 中文文件名编码问题:
关于文件名冲突问题
使用UUID对文件名进行重命名
package com.xiaohui.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Controller
public class FileUploadController {
@ResponseBody
@RequestMapping("fileUpload.do")
public String fileUpload(MultipartFile multipartFile, HttpServletRequest request) throws IOException {
//指定文件存储目录为当前项目部署环境下的upload目录
String realPath = request.getServletContext().getRealPath("/upload");
System.out.println(realPath);
File file = new File(realPath);
//判断目录存不存在,不存在则创建
if(!file.exists()){
file.mkdirs();
}
//获取文件名
String originalFilename = multipartFile.getOriginalFilename();
/*避免文件名冲突,使用UUID替换文件名*/
String uuid=UUID.randomUUID().toString();
String extendsName = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = uuid.concat(extendsName);
//文件存储位置
File outFile = new File(file,newFileName);
//文件保存
multipartFile.transferTo(outFile);
return "Ok";
}
}
控制文件类型、文件大小
package com.xiaohui.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Controller
public class FileUploadController {
@ResponseBody
@RequestMapping("fileUpload.do")
public Map<String,String> fileUpload(MultipartFile multipartFile, HttpServletRequest request) throws IOException {
Map<String, String> map = new HashMap<>();
//控制文件大小
if(multipartFile.getSize()>(1024*1024*5)){
map.put("message","文件大小不能超过5M");
return map;
}
//指定文件存储目录为当前项目部署环境下的upload目录
String realPath = request.getServletContext().getRealPath("/upload");
System.out.println(realPath);
File file = new File(realPath);
//判断目录存不存在,不存在则创建
if(!file.exists()){
file.mkdirs();
}
//获取文件名
String originalFilename = multipartFile.getOriginalFilename();
/*避免文件名冲突,使用UUID替换文件名*/
String uuid=UUID.randomUUID().toString();
//获取拓展名
String extendsName = originalFilename.substring(originalFilename.lastIndexOf("."));
//控制文件类型
if(!extendsName.equals(".jpg")){
map.put("message","文件类型必须是.jpg");
return map;
}
//生成新的文件名
String newFileName = uuid.concat(extendsName);
//文件存储位置
File outFile = new File(file,newFileName);
//文件保存
multipartFile.transferTo(outFile);
//上传成功后,把文件的名称和文件的类型返回给浏览器
map.put("message","上传成功");
map.put("newFileName",newFileName);
map.put("fileType",multipartFile.getContentType());
return map;
}
}
通过文件上传解析组件控制
但是会出现异常,后期可以可以配置一个异常解析器解决
<!--文件上传解析组件
id必须为multipartResolver
springmvc默认使用该id的组件
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSizePerFile" value="10"></property>
</bean>
上传图片回显问题
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
</head>
<script type="text/javascript">
$(function () {
$("#uploadFile").click(function () {
//获取要上传的文件
var photoFile = $("#photo")[0].files[0];
if (photoFile == undefined) {
alert("您还未选择文件");
return;
}
//将文件装入FromData对象中
var formData = new FormData();
formData.append("multipartFile", photoFile);
//ajax向后台发送文件
$.ajax({
type: "post",
data: formData,
url: "fileUpload.do",
processData: false,
contentType: false,
success: function (result) {
//接收后台响应的信息
console.log(result);
//图片回显
$("#headImg").attr("src","upload/"+result.newFileName);
}
})
})
})
</script>
<body>
<div style="text-align:center">
<h2>用户注册界面</h2>
<form action="addPlayer" method="get">
<p>账号:<input type="text" name="name"/></p>
<p>密码:<input type="password" name="password"/></p>
<p>昵称:<input type="text" name="nickname"/></p>
<p>
头像:<br/><input id="photo" type="file" name="photo"/><br/>
<img id="headImg" style="width:200px;height:200px" alt="你还未上传图片">
<br/><a id="uploadFile" href="javascript:void(0)">立即上传</a>
</p>
<p><input type="submit" name="注册"/></p>
</form>
</div>
</body>
</html>
进度条问题
https://www.cnblogs.com/wuyu1787/p/8919588.html
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
</head>
<style type="text/css">
.progress {
width: 600px;
height: 10px;
border: 1px solid #ccc;
border-radius: 10px;
margin: 10px 0px;
overflow: hidden;
}
/* 初始状态设置进度条宽度为0px */
.progress > div {
width: 0px;
height: 100%;
background-color: yellowgreen;
transition: all .3s ease;
}
</style>
<script type="text/javascript">
$(function () {
$("#uploadFile").click(function () {
//获取要上传的文件
var photoFile = $("#photo")[0].files[0];
if (photoFile == undefined) {
alert("您还未选择文件");
return;
}
//将文件装入FromData对象中
var formData = new FormData();
formData.append("multipartFile", photoFile);
//ajax向后台发送文件
$.ajax({
type: "post",
data: formData,
url: "fileUpload.do",
processData: false,
contentType: false,
success: function (result) {
//接收后台响应的信息
console.log(result);
//图片回显
$("#headImg").attr("src","upload/"+result.newFileName);
},
xhr: function() {
var xhr = new XMLHttpRequest();
//使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件
xhr.upload.addEventListener('progress', function (e) {
//loaded代表上传了多少
//total代表总数为多少
var progressRate = (e.loaded / e.total) * 100 + '%';
//通过设置进度条的宽度达到效果
$(".progress > div").css('width', progressRate);
})
return xhr;
}
})
})
})
</script>
<body>
<div style="text-align:center">
<h2>用户注册界面</h2>
<form action="addPlayer" method="get">
<p>账号:<input type="text" name="name"/></p>
<p>密码:<input type="password" name="password"/></p>
<p>昵称:<input type="text" name="nickname"/></p>
<p>
头像:<br/><input id="photo" type="file" name="photo"/><br/>
<img id="headImg" style="width:200px;height:200px" alt="你还未上传图片">
<div class="progress">
<div></div>
</div>
<br/><a id="uploadFile" href="javascript:void(0)">立即上传</a>
</p>
<p><input type="submit" name="注册"/></p>
</form>
</div>
</body>
</html>
单独准备文件存储服务器
分服务器上传作用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
应用服务器:负责部署我们的应用
在实际开发中,我们会有很多处理不同功能的服务器。(注意:此处说的不是服务器集群)
总结:分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
分服务器工作示意图
单独解压一个Tomcat作为文件服务器
设置远程服务器端口号
fileUploadServer\conf\server.xml
远程服务器中设置非只读
fileUploadServer\conf\web.xml
webapps下创建一个upload目录
然后启动测试
fileUploadServer\bin\startup.bat
如果这里运行加载的是其他目录下的启动包,需要把电脑中对Tomcat配置的环境变量进行删除。
启动测试
项目中导入依赖
<!--跨服务文件上传依赖-->
<!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-client -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19.4</version>
</dependency>
FileUploadController.java
package com.xiaohui.controller;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Controller
public class FileUploadController {
//文件存储位置
private final static String FILESSERVER = "http://192.168.43.93:8090/upload/";
@ResponseBody
@RequestMapping("fileUpload.do")
public Map<String, String> fileUpload(MultipartFile multipartFile, HttpServletRequest request) throws IOException {
Map<String, String> map = new HashMap<>();
//控制文件大小
if (multipartFile.getSize() > (1024 * 1024 * 5)) {
map.put("message", "文件大小不能超过5M");
return map;
}
//指定文件存储目录为当前项目部署环境下的upload目录
String realPath = request.getServletContext().getRealPath("/upload");
File file = new File(realPath);
//判断目录存不存在,不存在则创建
if (!file.exists()) {
file.mkdirs();
}
//获取文件名
String originalFilename = multipartFile.getOriginalFilename();
/*避免文件名冲突,使用UUID替换文件名*/
String uuid = UUID.randomUUID().toString();
//获取拓展名
String extendsName = originalFilename.substring(originalFilename.lastIndexOf("."));
//控制文件类型
if (!extendsName.equals(".jpg")) {
map.put("message", "文件类型必须是.jpg");
return map;
}
//生成新的文件名
String newFileName = uuid.concat(extendsName);
//创建sun公司提供的jersey包中client依赖
Client client = Client.create();
WebResource resource = client.resource(FILESSERVER + newFileName);
//文件保存到另外一个服务上
resource.put(String.class, multipartFile.getBytes());
//上传成功后,把文件的名称和文件的类型返回给浏览器
map.put("message", "上传成功");
map.put("newFileName", FILESSERVER + newFileName);
map.put("fileType", multipartFile.getContentType());
return map;
}
}
优化代码:
这里的IP代表本机的,参考下面文章,可以进行动态获取IP地址
https://www.cnblogs.com/zhi-leaf/p/10608911.html
@Controller
public class FileUploadController {
//获取本地IP地址
private LocalHostUtil localHostUtil;
//文件存储位置
private static String FILESSERVER;
static {
try {
//动态拼接IP地址
FILESSERVER = "http://"+LocalHostUtil.getLocalIP()+":8090/upload/";
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
@ResponseBody
@RequestMapping("fileUpload.do")
public Map<String, String> fileUpload(MultipartFile multipartFile, HttpServletRequest request) throws IOException {
Map<String, String> map = new HashMap<>();
//控制文件大小
if (multipartFile.getSize() > (1024 * 1024 * 5)) {
map.put("message", "文件大小不能超过5M");
return map;
}
//指定文件存储目录为当前项目部署环境下的upload目录
String realPath = request.getServletContext().getRealPath("/upload");
File file = new File(realPath);
//判断目录存不存在,不存在则创建
if (!file.exists()) {
file.mkdirs();
}
//获取文件名
String originalFilename = multipartFile.getOriginalFilename();
/*避免文件名冲突,使用UUID替换文件名*/
String uuid = UUID.randomUUID().toString();
//获取拓展名
String extendsName = originalFilename.substring(originalFilename.lastIndexOf("."));
//控制文件类型
if (!extendsName.equals(".jpg")) {
map.put("message", "文件类型必须是.jpg");
return map;
}
//生成新的文件名
String newFileName = uuid.concat(extendsName);
//创建sun公司提供的jersey包中client依赖
Client client = Client.create();
WebResource resource = client.resource(FILESSERVER + newFileName);
//文件保存到另外一个服务上
resource.put(String.class, multipartFile.getBytes());
//上传成功后,把文件的名称和文件的类型返回给浏览器
map.put("message", "上传成功");
map.put("newFileName", newFileName);
map.put("fileService", FILESSERVER);
map.put("fileType", multipartFile.getContentType());
return map;
}
}
index.jsp
优化后:
//图片回显
var headImgSrc = result.fileService + result.newFileName;
保存完整player信息进入数据库
PlayerController
package com.xiaohui.controller;
import com.xiaohui.pojo.Player;
import com.xiaohui.service.PlayerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PlayerController {
@Autowired
private PlayerService playerService;
@RequestMapping("addPlayer")
public String addPlayer(Player player){
//调用服务层方法,将数据存入数据库
int array = playerService.addPlayer(player);
System.out.println(array);
return "redirect:/showPlayer.jsp";
}
}
PlayerMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaohui.mapper.PlayerMapper">
<!--int addPlayer(Player player);-->
<insert id="addPlayer" parameterType="player">
insert into player values(DEFAULT ,#{name},#{password},#{nickname},#{photo},#{filetype})
</insert>
</mapper>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
</head>
<style type="text/css">
.progress {
width: 200px;
height: 10px;
border: 1px solid #ccc;
border-radius: 10px;
margin: 2px 0px;
overflow: hidden;
}
/* 初始状态设置进度条宽度为0px */
.progress > div {
width: 0px;
height: 100%;
background-color: yellowgreen;
transition: all .3s ease;
}
</style>
<script type="text/javascript">
$(function () {
$("#uploadFile").click(function () {
//获取要上传的文件
var photoFile = $("#photo")[0].files[0];
if (photoFile == undefined) {
alert("您还未选择文件");
return;
}
//将文件装入FromData对象中
var formData = new FormData();
formData.append("multipartFile", photoFile);
//ajax向后台发送文件
$.ajax({
type: "post",
data: formData,
url: "fileUpload.do",
processData: false,
contentType: false,
success: function (result) {
//接收后台响应的信息
console.log(result);
//图片回显
var headImgSrc = result.fileService + result.newFileName;
$("#headImg").attr("src",headImgSrc);
$("#photoInput").val(result.newFileName);
$("#filetypeInput").val(result.fileType);
},
xhr: function() {
var xhr = new XMLHttpRequest();
//使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件
xhr.upload.addEventListener('progress', function (e) {
//loaded代表上传了多少
//total代表总数为多少
var progressRate = (e.loaded / e.total) * 100 + '%';
//通过设置进度条的宽度达到效果
$(".progress > div").css('width', progressRate);
})
return xhr;
}
})
})
})
</script>
<body>
<div>
<h2>用户注册界面</h2>
<form action="addPlayer" method="get">
<p>账号:<input type="text" name="name"/></p>
<p>密码:<input type="password" name="password"/></p>
<p>昵称:<input type="text" name="nickname"/></p>
<p>
头像:<br/><input id="photo" type="file" /><br/>
<img id="headImg" style="width:200px;height:200px" alt="你还未上传图片">
<div class="progress">
<div></div>
</div>
<br/><a id="uploadFile" href="javascript:void(0)">立即上传</a>
<%--使用隐藏的输入框存储文件名称和文件类型--%>
<input id="photoInput" type="hidden" name="photo"/>
<input id="filetypeInput" type="hidden" name="filetype"/>
</p>
<p><input type="submit" name="注册"/></p>
</form>
</div>
</body>
</html>
showPlayer.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
this is showPlayer jsp
</body>
</html>
三、文件下载
showPlayer.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户一览画面</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
</head>
<style type="text/css">
#playerTable{
width: 50%;
border:3px solid cadetblue;
margin: 0px auto;
text-align: center;
}
#playerTable tr th,td{
border: 1px solid gray;
}
#playerTable tr td img{
width: 100px;
height: 100px;
}
</style>
<script type="text/javascript">
$(function (){
var MyIp="";
$.ajax({
type:"get",
url:"getIP",
success:function (data){
window.MyIp = "http://"+data;
}
});
$.ajax({
type:"get",
url:"getAllPlayers",
success:function (players){
$.each(players,function (i,e){
console.log(e);
$("#playerTable").append('<tr>\n' +
' <td>'+e.id+'</td>\n' +
' <td>'+e.name+'</td>\n' +
' <td>'+e.password+'</td>\n' +
' <td>'+e.nickname+'</td>\n' +
' <td>\n' +
' <img src="'+window.MyIp+':8090/upload/'+e.photo+'" alt="">\n' +
' </td>\n' +
' <td>\n' +
' <a href="fileDownLoad?photo='+e.photo+'&filetype='+e.filetype+'">下载</a>\n' +
' </td>\n' +
' </tr>')
})
}
})
})
</script>
<body>
<table id="playerTable" cellspacing="0px" cellpadding="0px">
<tr>
<th>编号</th>
<th>用户名</th>
<th>密码</th>
<th>昵称</th>
<th>头像</th>
<th>操作</th>
</tr>
</table>
</body>
</html>
PlayerController.java
//获取所有用户胡信息
@ResponseBody
@RequestMapping("getAllPlayers")
public List<Player> getAllPlayer() throws UnknownHostException {
List<Player> palters = playerService.getAllPlayer();
String localIP = LocalHostUtil.getLocalIP();
return palters;
}
//动态获取本地IP
@ResponseBody
@RequestMapping("getIP")
public String getIP() throws UnknownHostException {
return LocalHostUtil.getLocalIP();
}
FileUploadController.java
/**
* @功能描述:文件下载
*/
@RequestMapping("fileDownLoad")
public void fileDownLoad(String photo, String filetype, HttpServletResponse response) throws IOException {
//设置响应头
response.setHeader("Content-Disposition","attachment;filename="+photo);
//告诉浏览器要将数据保存在磁盘上,不在浏览器上直接解析
response.setContentType(filetype);
//告诉浏览文件下载的文件类型
InputStream inputStream = new URL(FILESSERVER + photo).openStream();
//获取一个指向浏览器的输出流
ServletOutputStream outputStream = response.getOutputStream();
//向浏览器响应文件即可
IOUtils.copy(inputStream,outputStream);
}
四、拦截器
- Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
- 要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
- 1.通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。
- 2.通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。
- 要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
定义一个拦截器,实现接口 HandlerInterceptor
package com.xiaohui.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/**
* 在请求到达我们定义的handler之前工作的
*/
System.out.println("MyInterceptor preHandle");
//返回是true,代表放行,可以继续到达handler
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
/**
* handler 处理单元返回ModelAndView 时候进行 拦截
*/
System.out.println("MyInterceptor postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
/**
* 页面渲染完毕,但是还没有给浏览器响应数据的时候
*/
System.out.println("MyInterceptor afterCompletion");
}
}
springmvc.xml中注册拦截器
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/login.action"/>
<bean id="myInterceptor" class="com.msb.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器方法及内容详解
1、preHandle方法
- 执行时机
- 再进入控制单元方法之前执行
- 如何调用
- 按拦截器定义顺序调用
- 具体作用
- 如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去 进行处理,则返回 true。 如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
- 参数详解
- HttpServletRequest arg0,拦截的请求的request对象
- HttpServletResponse arg1, 拦截的请求的response对象
- Object arg2 封存了单元方法对象的HandleMethod对象
/**
* @功能描述:
* @Param request 请求对象
* @Param response 响应对象
* @Param handler 目标要回调的handler
* @return 返回true放行,返回false拦截
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/*在请求到达我们定义的handler之前工作的*/
System.out.println("MyInterceptor preHandle");
/*设置请求和响应的乱码*/
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
//判断用户是否登录
// User user = (User) request.getSession().getAttribute("user");
// if(null == user){
// response.sendRedirect("index.jsp");
// return false;
// }
//用户权限控制
//返回是true,代表放行,可以继续到达handler
return true;
}
2、postHandle方法
- 执行时机
- 在进行数据处理和做出响应之间进行这个方法的调用
- 如何调用
- 在拦截器链内所有拦截器返成功调用
- 具体作用
- 在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,
- 在该方法中对用户请求 request域数据进行处理。
- 参数详解
- HttpServletRequest arg0, 拦截的请求的request对象
- HttpServletResponse arg1, 拦截的请求的response对象
- Object arg2, 封存了单元方法对象的HandleMethod对象
- ModelAndView arg3 封存了单元方法的返回值资源路径和请求转到的Map数据
MyInterceptor.java
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
/*handler 处理单元返回ModelAndView 时候进行 拦截*/
System.out.println("MyInterceptor postHandle");
//控制数据
Map<String, Object> model = modelAndView.getModel();
String message = (String) model.get("message");
String newMessage = message.replaceAll("脏话", "**");
model.put("message", newMessage);
//控制视图
// modelAndView.setViewName("/index.jsp");
}
UserController.java
@RequestMapping("login.do")
public ModelAndView login(String uname, String password) {
System.out.println("UserController");
ModelAndView modelAndView = new ModelAndView();
Map<String, Object> model = modelAndView.getModel();
model.put("message","脏话,你好");
User user = userService.findUser(uname, password);
if (null != user) {
modelAndView.setViewName("/success.jsp");
} else {
modelAndView.setViewName("/fail.jsp");
}
return modelAndView;
}
3、afterCompletion方法
- 执行时机
- 在进行页面渲染的时候执行
- 如何调用
- 按拦截器定义逆序调用
- 具体作用
- 在DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
- 参数详解
- HttpServletRequest arg0, 拦截的请求的request对象
- HttpServletResponsearg1, 拦截的请求的response对象
- Object arg2, 封存了单元方法对象的HandleMethod对象
- Exception arg3 存储了责任链的异常信息
/**
* @功能描述:无论controller是否出现异常,都会执行的方法,一般来说都做一些资源释放工作
* @Param
* @return
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
/*页面渲染完毕,但是还没有给浏览器响应数据的时候*/
System.out.println("MyInterceptor afterCompletion");
System.out.println(ex);
}
多个拦截器执行顺序
多个拦截器同时存在时,执行的顺序由配置顺序决定. 先配置谁, 谁就先执行.多个拦截器可以理解为拦截器栈, 先进后出(后进先出), 如图所示:
再复制一个拦截器文件,并把拦截器注入到容器中,
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/login.do"/>
<bean id="myInterceptor1" class="com.xiaohui.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/login.do"/>
<bean id="myInterceptor2" class="com.xiaohui.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
结果:
MyInterceptor preHandle
MyInterceptor2 preHandle
UserController
MyInterceptor2 postHandle
MyInterceptor postHandle
/success.jsp
MyInterceptor2 afterCompletion
MyInterceptor afterCompletion
五、异常处理
系统中异常包括两类:预期异常(检查型异常)和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息, 后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理,如下图
异常具体实现方法
1、使用@ExceptionHandler注解处理异常
缺点:只能处理当前Controller中的异常。
package com.xiaohui.controller;
import org.aspectj.weaver.ast.Var;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class ExceptionController {
@RequestMapping("test01.action")
public String test01(){
int i=1/0;
return "success.jsp";
}
@RequestMapping("test02.action")
public String test02(){
String s=null;
System.out.println(s.length());
return "success.jsp";
}
@ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
public ModelAndView handelException(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error1.jsp");
return modelAndView;
}
}
2、使用:@ControllerAdvice+@ExceptionHandler
全局异常处理,如果某个controller中定义了异常处理方法,则该controller优先执行内部异常处理方法,如果没有则执行全局的异常处理方法。
首先创建一个exceptionhandler》GloableExceptionHandler1,java
在容器中添加对exceptionhandler目录下的文件扫描
applicationContext.xml
<context:component-scan base-package="com.xiaohui.service,com.xiaohui.exceptionhandler"></context:component-scan>
GloableExceptionHandler1,java
package com.xiaohui.exceptionhandler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class GloableExceptionHandler1 {
@ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
public ModelAndView handelException(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error1.jsp");
return modelAndView;
}
}
在UserController.java定义一个异常信息
@RequestMapping("login.do")
public ModelAndView login(String uname, String password) {
System.out.println("UserController");
ModelAndView modelAndView = new ModelAndView();
Map<String, Object> model = modelAndView.getModel();
model.put("message","脏话,你好");
User user = userService.findUser(uname, password);
if (null != user) {
modelAndView.setViewName("success.jsp");
} else {
modelAndView.setViewName("fail.jsp");
}
int i=1/0;
return modelAndView;
}
结果:
3、使用:SimpleMappingExceptionResolver
使用xml注解方式注入到容器中进行异常处理,这里对于xml配置后需要把原有的异常处理方法给删除调
springmvc.xml
<!--异常处理-->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">redirect:/error1.jsp</prop>
<prop key="java.lang.NullPointerException">redirect:/error2.jsp</prop>
</props>
</property>
</bean>
结果:
使用配置类进行配置
创建config》GloableException2.java
package com.xiaohui.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Properties;
@Configuration
public class GloableException2 {
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.put("java.lang.NullPointerException","error1.jsp");
prop.put("java.lang.ArithmeticException","error2.jsp");
resolver.setExceptionMappings(prop);
return resolver;
}
}
添加config目录的包扫描
<context:component-scan base-package="com.xiaohui.service,com.xiaohui.config"></context:component-scan>
结果和上述一样
4、自定义的HandlerExceptionResolver
package com.xiaohui.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class GloableException3 implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView modelAndView = new ModelAndView();
if(e instanceof ArithmeticException){
modelAndView.setViewName("error1.jsp");
}
if(e instanceof NullPointerException){
modelAndView.setViewName("error2.jsp");
}
modelAndView.addObject("message",e.getMessage());
return modelAndView;
}
}
结果:
六、其他注解
SpringMVC中注解完善
- 1、@PostMapping
- 作用:
- 指定当前发送请求的方式只可以是post请求
- 属性:
- 和@RequestMapping中属性一致
- 作用:
代码实现
@PostMapping("/userControllerA")
public String userControllerA(){
return "forward:/success.jsp";
}
- 2、@GetMapping
- 作用:
- 指定当前发送请求的方式只可以是get请求
- 属性:
- 和@RequestMapping中属性一致
- 作用:
代码实现:
@GetMapping("/userControllerA")
public String userControllerA(){
return "forward:/success.jsp";
}
- 3、@RestController
- 作用:
- 书写到类上,代表该类中所有控制单元方法均是ajax响应 相当于@ResponseBody+@Controller
- 属性:
- 其中的属性和@Controller中一样
- 作用:
代码实现:
@RestController
public class UserController {
}
- 4、@JsonFormat
- 作用:
- 处理响应json 数据的处理
- 属性:
- pattern :指定响应时间日期的格式
- Timezone:指定响应的时区,否则会有8个小时的时间差
- 作用:
代码实现:
package com.xiaohui.pojo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
private String ename;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
private Date birthday;
}
package com.xiaohui.controller;
import com.xiaohui.pojo.Emp;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class DateFormatController {
@RequestMapping("testDate")
@ResponseBody
public Emp testDate(Emp emp){
System.out.println(emp);
return emp;
}
}
dateFormat.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
</head>
<script type="text/javascript">
$(function(){
$.ajax({
url:"testDate",
data:"ename=aaa&birthday=2020-01-01",
type:"get",
success:function(result){
console.log(result)
}
})
})
</script>
<body>
this is dataFormat jsp
</body>
</html>
5、@RequestBody
- 作用:
- 用于获取请求体json格式的字符串内容。直接使用得到是 key=value&key=value…结构的数据,get 请求方式不适用。
- 属性:
- required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get 请求得到是null。
- 实现:
@RequestMapping("testDate")
@ResponseBody
public Emp testDate(@RequestBody(required = false) Emp emp){
System.out.println(emp);
return emp;
}
dateFormat.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
</head>
<script type="text/javascript">
$(function(){
var jsonObj = {ename:"张三",birthday:"2020-01-01"};
var newData = JSON.stringify(jsonObj);
$.ajax({
url:"testDate",
data:newData,
type:"post",
contentType:"application/json",
success:function(result){
console.log(result)
}
})
})
</script>
<body>
this is dataFormat jsp
</body>
</html>
6、@CrossOrigin
- 什么是跨域
- 出于浏览器的同源策略限制。同源策略(SameOriginPolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
http://127.0.0.1:8080/msb/index.jsp基础
https://127.0.0.1:8080/msb/index.jsp 协议不一样
http://192.168.24.11:8080/msb/index.jsp IP不一致
http://127.0.0.1:8888/msb/index.jsp 端口不一致
http://localhost:8080/msb/index.jsp IP不一致
- 出于浏览器的同源策略限制。同源策略(SameOriginPolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
- 作用:
- 解决ajax请求之间的跨域问题
- 属性:
- origins : 允许可访问的域列表IP
- maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。
代码实现:
@Controller
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
public class DateFormatController {
@RequestMapping("testDate")
@ResponseBody
public Emp testDate(@RequestBody(required = false) Emp emp){
System.out.println(emp);
return emp;
}
}