回顾
文件上传
前端三要素
文件上传表单项为 file类型且有name属性
表单请求方式 post
表单enctype属性:"multipart/form-data" 多部分表单提交
后台
导入fileupload和io依赖
项目只需要配置multipartResovler(名字固定)
在方法参数中声明MultipartFile类型参数,名字和input的标签的name属性保持一致.
在方法中对文件进行操作
请求相关注解
@RequestParam
当请求过来的数据和方法中参数不一致的时候,可以使用此注解形成对应关系.还可以设置默认值,还可以将页面上的同名参数封装成list
value 指定参数名
defaultValue 设置默认值
了解@RequestHeader 获取请求头信息
了解@CookieValue 获取指定cookie的值
获得原生ServletAPI(request,response,session)
方式1:方法上声明参数
方式2:注入
静态资源放行
方式1:开启静态资源servlet支持
<mvc:default-servlet-handler/>
方式2:映射静态资源路径
<mvc:resources mapping="/img/**" location="/img/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
方式3:修改前端控制器的匹配路径 常用*.do
springMVC响应(方法的返回值)
string:
1.默认转发
2.使用forward关键字完成转发,可以使用map modelmap model往request域中存放数据
3.使用redirect关键字完成重定向
站外资源:写路径
站内资源:内部路径,和转发的路径写法一样
void:使用原生的api完成响应操作
ModelAndView:
可以设置数据
可以设置跳转的视图
@SessionAttributes:作用在类上,将数据转存到session中
ajax:
使用下面这两个注解务必导入jackson依赖.
@RequestBody:将json数据封装成指定的javabean或者map
@ResponseBody:将方法的返回值转成json返回给浏览器
Restful
通过请求路径+请求方式来简化路径编写
- 查询操作 发送get请求 /user/2/tom
- 删除操作 发送delete请求 /user/2
- 保存操作 发送post请求 /user
- 更新操作 发送put请求 /user
@PathVariable 获取路径上的/user/{id}的id值,赋值给方法的参数
@RestController 等价于 @ResponseBody+@Controller
全局异常处理器
异常最终抛给DispatcherServlet,在web层也抛
web方式
通过error-page标签配置404和500状态码跳转的路径
springmvc方式
xml方式
编写异常处理器类实现HandlerExceptionResolver
配置异常处理器交给IOC容器
注解方式
编写一个类,添加@ControllerAdvice
在类中编写方法,在方法上通过@ExceptionHandler的value属性声明处理哪些异常
内容介绍
- 拦截器.类似过滤器
- SSM整合(掌握)
- spring + springMVC + Mybatis
一 SpringMVC的拦截器
1 介绍
SpringMVC的拦截器类似于web阶段所学的filter过滤器,对处理器(方法)进行前置 和后置 拦截操作。
filter可以过滤拦截web工程中任意请求,springmvc中拦截器只能拦截当前框架环境中的方法.
2 快速入门
步骤分析:
- 导入模块
- 模块中有一个Controller,提供了三个方法
- 名字 – 路径
- test1 – test1
- test2 – test2
- test3 – test/test3
- 编写一个拦截器,实现一个接口 HandlerInterceptor
- 选择需要重写方法(3个方法)
- 在springmvc.xml中配置拦截器的拦截规则
- 对那些路径进行拦截
- 对所有的路径进行拦截
- 忽略拦截规则中一些方法
- 放行 test2
- 对那些路径进行拦截
- 测试
代码实现:
拦截器
public class HelloInterceptor1 implements HandlerInterceptor {
@Override
//目标方法执行之前的操作
/*
返回值:是否放行
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("1 -- preHandle执行了");
return true;
}
@Override
//目标方法执行之后的操作,视图渲染之前
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("1 -- postHandle 执行了");
}
@Override
//视图渲染之后的操作
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("1 -- afterCompletion 执行了");
}
}
controller
@Controller
@RequestMapping("demo")
public class DemoController {
@RequestMapping(value="test1",method = RequestMethod.GET)
public String test1(){
System.out.println("test1 方法执行了");
return "success";
}
@RequestMapping(value="test2",method = RequestMethod.GET)
public String test2(){
System.out.println("test2 方法执行了");
return "success";
}
@RequestMapping(value="test/test3",method = RequestMethod.GET)
public String test3(){
System.out.println("test3 方法执行了");
return "success";
}
}
springmvc.xml
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--
mapping标签的path配置对那些路径进行拦截,可以出现多次
支持通配符 *
/demo/* 只拦截demo下的一层路径 例如:/demo/test1和/demo/test2,但是不拦截/demo/test/test3
/demo/** 拦截demo下的所有路径 例如:/demo/test1 , /demo/test2,/demo/test/test3
exclude-mapping标签的path用来配置上面拦截的基础上放行那些路径,可以出现多次
-->
<mvc:mapping path="/demo/**"/>
<mvc:exclude-mapping path="/demo/test2"/>
<!--配置拦截器-->
<bean class="com.itheima.web.interceptor.HelloInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
3 拦截器链
多个拦截器对我们同一个controller进行拦截,这些拦截器就是拦截器链,他们的执行顺序是由在xml中的顺序决定的.
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/demo/**"/>
<mvc:exclude-mapping path="/demo/test2"/>
<bean class="com.itheima.web.interceptor.HelloInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/demo/test1"/>
<bean class="com.itheima.web.interceptor.HelloInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
4 案例:简易权限拦截器
需求
用户没有登录的情况下,不能访问用户中心,点击用户中心连接会拦截并跳转到登录页面 ; 只能用户登录后才可以访问用户中心页面。
说明:
- 在index.jsp上有两个连接
- /springmvc/user/toLogin 跳转到登陆页面
- /springmvc/user/homeIndex 跳转到用户中心页面
- 在UserController中提供3个方法
- toLogin 跳转到登录页
- homeIndex 跳转到用户中心页面
- login 登陆操作
步骤分析
- 编写一个拦截器 LoginPermissionInterceptor
- 只需要重写preHandler方法
- 判断session中有否用用户
- 若有,放行
- 若无,设置错误信息,转发到login.jsp
- 判断session中有否用用户
- 只需要重写preHandler方法
- 在springmvc.xml中配置拦截器
- 拦截用户下的所有方法
- 放行和登陆相关的方法
- 测试
代码实现
LoginInterceptor
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断用户是否登陆,若登陆则放行;若没有登陆就跳转到登录页
Object loginUser = request.getSession().getAttribute("loginUser");
if (null == loginUser) {
//没有登陆
request.setAttribute("msg","请先登录");
request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request,response);
return false;
}
return true;
}
}
LoginInterceptor拦截器配置
<!--以下代码放在springmvc.xml中mvc:interceptors标签下-->
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<mvc:exclude-mapping path="/user/login"/>
<mvc:exclude-mapping path="/user/toLogin"/>
<bean class="com.itheima.web.interceptor.LoginInterceptor"/>
</mvc:interceptor>
二 SSM框架整合
1 需求
使用ssm框架完成对account
表的增删改查操作。
注意:事务
2 步骤分析
- 新建web模块ssm_account
- 导入依赖
- web:servlet jsp jstl spring-webmvc
- service:spring-jdbc aspectjweaver
- dao:驱动 druid mybatis
- 单元测试
- 日志(稍后)
- spring整合mybatis的包:mybatis-spring
- 导入配置文件
- db.properties
- 日志配置
- 导入依赖
- 创建Account
- 保证dao层独立运行
- 保证service独立运行
- 整合service和dao
- 保证web层独立运行
- 整合service和web
- 添加事务控制
- 添加日志
三 SSM整合代码实现
0 最终pom
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</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>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<!--spring整合mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
1 保证dao层独立运行
- 创建Account
- 提供AccountMapper及其映射文件
- 提供mybatis的核心配置文件
- 测试
public class Account {
private Integer id;
private String name;
private Integer money;
}
public interface AccountMapper {
List<Account> findAll();
}
<?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.itheima.dao.AccountMapper">
<select id="findAll" resultType="account">
select * from account
</select>
</mapper>
核心配置文件不用敲
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--别名配置-->
<typeAliases>
<package name="com.itheima.domain"/>
</typeAliases>
<!--环境配置-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///springdb"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<!--映射文件配置-->
<mappers>
<package name="com.itheima.dao"/>
</mappers>
</configuration>
测试代码一定不要敲
public class TestDao {
@Test
public void testDao() throws IOException {
//加载配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//创建SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//获取session
SqlSession sqlSession = factory.openSession();
//获取dao
AccountMapper accountMapper = sqlSession.getMapper(AccountMapper.class);
//调用dao中的方法
List<Account> list = accountMapper.findAll();
System.out.println(list);
//提交事务和释放资源
sqlSession.commit();
sqlSession.close();
}
}
2 保证service独立运行
- 编写AccountService及其实现类
- 添加注解 @Service
- 编写applicationContext.xml
- 开启组件扫描
- 测试
@Service
public class AccountServiceImpl implements AccountService {
@Override
public List<Account> findAll() {
System.out.println("service执行了");
return null;
}
}
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--组件扫描-->
<context:component-scan base-package="com.itheima"/>
</beans>
@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestService {
@Autowired
AccountService accountService;
@Test
public void testService(){
System.out.println(accountService.findAll());
}
}
3 整合service和dao
spring整合其他框架 说白了就是找到要整合框架中的单实例对象,将这些对象交给spring管理即可
mybatis中哪些对象是我们需要单实例呢?
- 连接池
- SqlSessionFactory对象
- 每个Dao的代理对象
- 导入依赖 mybatis-spring.xxx.jar
- 在spring配置文件中
- 加载db.properties
- 配置数据源
- SqlSessionFactory对象 (SqlSessionFactoryBean类)
- 注入数据源
- 配置domain的别名
- 每个dao的代理对象(MapperScannerConfigurer)
- 注入dao包的位置
- 在AccountServiceImpl中注入mapper对象
- 再次测试service
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--加载配置文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--整合mbyatis-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
<!--配置别名-->
<property name="typeAliasesPackage" value="com.itheima.domain"/>
</bean>
<!--扫描指定包及其子包下的所有接口,产生代理对象放入spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--配置需要扫描的包-->
<property name="basePackage" value="com.itheima.dao"/>
</bean>
</beans>
4 保证web层独立运行
- 创建AccountController
- 编写index.jsp,在index.jsp上新建一个连接,指向查询所有的操作
- 在web-inf/pages/account下编写account-list.jsp,在jsp中展示所有的账户
- 编写springmvc.xml
- 扫描所有的controller
- mvc注解支持
- 视图解析器
- 静态资源放行
- 在web.xml中编写前端控制器和字符编码过滤器
@Controller
@RequestMapping("account")
public class AccountController {
@RequestMapping("list")
public String findAll(){
System.out.println("ctrl中方法执行了");
return "account/account-list";
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table align="center" border="1" width="40%">
<tr>
<th>id</th>
<th>姓名</th>
<th>余额</th>
</tr>
<c:forEach items="${list}" var="account">
<tr align="center">
<td>${account.id}</td>
<td>${account.name}</td>
<td>${account.money}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
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: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
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.itheima.web"/>
<!--开启mvc注解支持-->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--静态资源放行-->
<mvc:default-servlet-handler/>
</beans>
web.xml
<!--前端控制器-->
<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>
<!--字符编码过滤器-->
<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>
5 整合service和web
思考:
- spring的容器需要几个?
- spring的容器什么时候创建?
- 咱们怎么就知道项目启动了?
- 创建好的容器对象放到哪里,所有的controller(Servlet)可以访问到?
- 创建spring容器的需要指定什么?
- 配置文件路径应该在哪里指定?
- spring的容器需要几个?1个
- spring的容器什么时候创建?项目启动的时候创建
- 咱们怎么就知道项目启动了?可以使用ServletContextListener监听servletContext对象的创建.对象创建好了就代表项目启动成功了.
- 创建好的容器对象放到哪里,所有的controller(Servlet)可以访问到?ServletContext域中
- 创建spring容器的需要指定什么?spring的配置文件
- 配置文件路径应该在哪里指定?项目的初始化参数中
spring已经将上面的操作都封装好了,
- 导入一个依赖(spring-web)
- 在web.xml中通过context-param配置spring文件的位置
- 在web.xml配置一个spring提供好的监听器:ContextLoaderListener
- 在web(controller)中注入service即可
在项目启动的时候,加载web.xml中context-param中配置的spring配置文件,创建spring容器,将容器放入ServletContext域中
springmvc是spring的一部分,导入依赖的操作省略,只需要在web.xml中配置以下内容即可
<!--配置service和dao的配置文件的路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
6 添加事务控制
在applicationContext.xml中配置
- 事务管理器
- 通知的规则(什么方法使用那种隔离级别,传播行为,是否只读,超时时间等)
- aop配置(主要配置切入点,使用spring提供好的通知)
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务运行规则-->
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--aop配置-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.itheima.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
7 添加日志
- 导入依赖:log4j,slf4j,slf4j和log4j整合依赖
- 复制log4j.properties文件到resources目录下
<!--日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
扩展阅读:java日志门面
- https://www.cnblogs.com/xrq730/p/8619156.html
四 完成账户的保存操作
分析:
- 在AccountMapper中提供save(Account account),编写映射文件
- 在AccountService中提供save(Account account),在方法中调用dao的save方法
- 在AccountController提供save(Account account),在方法中调用service的save方法
- 在web-inf/pages/account提供一个添加账户的表单页面 account-add.jsp
- 在index.jsp上提供一个连接,能够转发到account-add.jsp
代码实现
AccountMapper和AccountService
void save(Account account);
映射文件
<insert id="save">
insert into account values (null,#{name},#{money})
</insert>
AccountController
@RequestMapping("save")
public String save(Account account){
accountService.save(account);
return "redirect:/account/list";
}
@RequestMapping("saveUI")
public String saveUI(){
return "account/account-add";
}
五 spring容器和springmvc容器关系
三大组件的初始化时机:
listener > filter > servlet
也就是spring容器先于springmvc容器初始化
了解下ContextLoaderListener做了那些操作.