springMVC相关
SpringMVC前言
由来:
基于spring框架基础之上开发的一个全新的框架
目的:
为了使现有项目中使用spring框架在mvc架构中存在自己的位置,因此开发了一个springmvc框架
MVC:
编程步骤 三层编程
- M : model 模型 service+dao+entity
- V : view 视图 webapp页面
- C:Controller 控制器 action
为了使Spring可插入的MVC架构,SpringFrameWork在Spring基础上开发SpringMVC框架,从而在使用Spring进行WEB开发时可以选择
使用Spring的SpringMVC框架作为web开发的控制器框架
为什么是SpringMVC?
- Spring框架流行程度非常之高 ----可以与Spring框架进行无缝整合
- 运行效率高于Struts2
- 注解式开发更高效
SpringMVC的特点
SpringMVC轻量级,典型MVC框架,在整个MVC架构中充当控制器框架,相对于之前学习的struts框架,SpringMVC运行更快,其注解式开发更高效灵活
SpringMVC流程
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
组件说明
1、前端控制器DispatcherServlet(不需要工程师开发),由框架提供
作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4、处理器Handler(需要工程师开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。
5、视图解析器View resolver(不需要工程师开发),由框架提供
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。
6、视图View(需要工程师开发jsp...)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)
SpringMVC中数据传递机制
数据存储方式:
-
request
-
session
-
application
数据在页面如何获取:
-
EL表达式
数据如何展示:
-
EL+JSTL标签展示
存数据具体使用哪种作用域:
-
跳转方式
- forward: 一次请求 request 作用域
- redirect: 多次请求 session作用域 application作用域[不推荐] ?地址栏传递数据
如何在SpringMVC控制器方法中获取Request对象,Response对象?
-
//注意 : 直接将request response对象作为控制器方法参数声明即可获取 public String findAll(HttpServletRequest request,HttpServletResponse response) { request.getSession(); request.getServletContext(); }
SpringMVC中静态资源拦截问题
**原因 : **
由于在web.xml中配置SpringMVC的核心Servlet DispatcherServlet 时 url-pattern 配置为 "/",因此会导致项目中所有 / 开头请求,均被作为控制器请求处理,这样会导致项目中的静态资源(css,js,img)被拦截.
**解决方案 : **
-
url-pattern / 导致静态资源拦截 *.action
-
使用这种方式 日后访问路径结尾必须加入指定后缀 url.action
-
url-pattern 依然使用 /
-
配置对全部资源放行
-
<!--全部资源放行--> <mvc:default-servlet-handler/>
-
对指定目录下的资源放行
-
<!-- 对指定目录下的静态资源放行 --> <mvc:resources location="/images/" mapping="/images/**"/> <mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/js/" mapping="/js/**"/>
-
SpringMVC中拦截器
拦截器 Interceptor 拦截 中断,类似于JAVAWEB中的Filter 只不过Interceptor只能拦截控制器请求
作用 :
- 通过将控制器中的通用代码放在拦截器中执行,减少控制器中代码的冗余
拦截器特点
- 请求到达会经过拦截器 响应回来同样会经过拦截器
- 拦截器只能拦截控制器相关请求 不能拦截jsp 静态资源 相关请求
- 拦截器可以中断请求轨迹(不放行,请求终端)
开发拦截器
- 类 implements HandlerInterceptor 实现接口中方法
public class MyInterceptor implements HandlerInterceptor {
// 1. 请求经过拦截器会优先进入拦截其中preHandle方法执行preHandle方法中的内容
// 2. 如果preHandle 返回为 true 代表放行请求,如果返回为 false 代表中断请求
// 3. 如果preHandle 返回为true,会执行当前请求中对应控制器的方法
// 4. 当控制器方法执行结束之后,会返回拦截器中 postHandle 方法
// 5. postHandle 执行完成之后会响应请求,在响应请求完成后会执行afterCompletion方法
@Override
//参数1 : 当前请求对象 参数2 : 当前请求对应响应对象 参数3 : 当前请求的控制器对应的方法对象
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("===1===");
return true;
}
@Override
//参数1 : 当前请求对象 参数2 : 当前请求对应响应对象 参数3 : 当前请求的控制器对应的方法对象 参数4 : 当前请求控制器返回的modelAndView
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("===2===");
}
@Override
//注意 : 无论正确还是失败都会执行
//参数1 : 当前请求对象 参数2 : 当前请求对应响应对象 参数3 : 当前请求的控制器对应的方法对象 参数4 : 请求过程中出现异常时异常对象
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("===3===");
}
}
- 配置拦截器
- a).注册拦截器对象
- b).配置拦截器拦截的请求路径
<!--注册拦截器-->
<bean id="myInterceptor" class="com.longda.interceptors.MyInterceptor"></bean>
<!--配置拦截器-->
<mvc:interceptors>
<!--配置一个拦截器-->
<mvc:interceptor>
<!--mvc:mapping 代表拦截哪个请求路径-->
<mvc:mapping path="/json/*"/>
<!--放行哪个请求-->
<mvc:exclude-mapping path="/json/showAll"/>
<!--使用哪个拦截器-->
<ref bean="myInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
SpringMVC中全局异常处理机制
SpringMVC作为一个控制器主要作用
- 处理请求 接受请求数据 调用业务对象
- 请求响应 跳转对应视图展示数据
现有控制器开发存在问题
- 在处理用户请求出现运行时异常时直接相应给用户的是一个错误界面,对于用户的使用体验不好
全局异常处理机制
作用:
用来解决整合系统中任意一个控制器抛出异常时的统一处理入口
全局异常处理开发
-
类 implements HandlerExceptionResolver
-
public class MyExceptionHandler implements HandlerExceptionResolver{ @Override //用来处理发生异常时方法 // 参数1 当前请求对象 参数2 当前请求对象的响应对象 参数3 当前请求的方法对象 参数4 当前出现异常时的异常对象 返回值 出现异常时展示视图和数据 public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView modelAndView = new ModelAndView(); //基于不同业务异常跳转到不同页面 if(ex instanceof UserNameNotFoundException) { //instanceof 判断参数类型 modelAndView.setViewName("redirect:/login.jsp"); } else { modelAndView.setViewName("redirect:/error.jsp"); //跳转到error.jsp } return modelAndView; } }
-
-
配置全局异常处理类
-
<bean id="" class="xxx.xxx.xxExceptionResolver"></bean>
-
ssm框架整合
1 新建maven项目,添加web支持
2 maven依赖导入
<dependencies>
<!--Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!--Servlet - JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
</dependencies>
3 maven资源过滤设置
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
4 建立基本项目结构和配置框架
-
com.LongDa.pojo
-
com.LongDa.dao
-
com.LongDa.service
-
com.LongDa.controller
-
mybatis-config.xml
-
mybatis-config.xml(mybatis的)
<?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></configuration>
-
applicationContext.xml(spirng的)
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"></beans>
Mybatis层编写
1 数据库配置文件database.properties
这里要注意设置时区
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/ssmbuild?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
username=root
password=123456
2 编写mybatis核心配置
<?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.LongDa.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.LongDa.dao.BookMapper"/>
</mappers>
</configuration>
4 编写数据库对应的实体类
记得添加lombok依赖
package com.LongDa.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class books {
private int bookID;
private String bookName;
private int bookCounts;
private String detail;
}
5 编写Dao层的Mapper接口
public interface BookMapper {
List<books> queryAllBooks();
books queryBookByOne(int id);
int addBook(books book);
int deleteBook(books book);
int updateBook(books book);
}
6 编写对应的Mapper.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.LongDa.dao.BookMapper">
</mapper>
这里我用注解写了
public interface BookMapper {
@Select("select * from books")
List<books> queryAllBooks();
@Select("select * from books where bookID = #{id}")
books queryBookByOne(@Param("id") int id);
@Insert("insert into books(bookID,bookName,bookCounts,detail) values #{book.bookID},#{book.bookName},#{book.bookCounts},#{book.detail},")
int addBook(books book);
@Delete("delete from books where bookID = #{id}")
int deleteBook(@Param("id") int id);
@Update("update books set bookName = #{bookName},bookCounts = #{bookCounts},detail = #{detail} where bookID = #{bookID}")
int updateBook(books book);
}
7 编写Service层接口和实现类
接口:
public interface BookService {
List<books> queryAllBooks();
books queryBookByOne(int id);
int addBook(books book);
int deleteBook(@Param("id") int id);
int updateBook(books book);
}
实现类:
public class BookServiceImpl implements BookService {
private BookMapper bookMapper;
public void setBookMapper(BookMapper bookMapper) {
this.bookMapper = bookMapper;
}
public List<books> queryAllBooks() {
return bookMapper.queryAllBooks();
}
public books queryBookByOne(int id) {
return bookMapper.queryBookByOne(id);
}
public int addBook(books book) {
return bookMapper.addBook(book);
}
public int deleteBook(int id) {
return bookMapper.deleteBook(id);
}
public int updateBook(books book) {
return bookMapper.updateBook(book);
}
}
Spring层整合
1 数据源使用c3p0
2 我们去编写Spring整合Mybatis的相关的配置文件;spring-dao.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置整合mybatis -->
<!-- 1.关联数据库文件 -->
<context:property-placeholder location="classpath:database.properties"/>
<!-- 2.数据库连接池 -->
<!--数据库连接池
dbcp 半自动化操作 不能自动连接
c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性 -->
<property name="driverClass" value="${driverClassName}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="user" value="${username}"/>
<property name="password" value="${password}"/>
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 4.配置扫描Dao接口包,动态实现Dao接口注入到spring容器中 -->
<!--解释 :https://www.cnblogs.com/jpfss/p/7799806.html-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="com.LongDa.dao"/>
</bean>
</beans>
3、Spring整合service层
<?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"> <!-- 扫描service相关的bean --> <context:comp<?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">
<!-- 扫描service相关的bean -->
<context:component-scan base-package="com.LongDa.service" />
<!--BookServiceImpl注入到IOC容器中-->
<bean id="BookServiceImpl" class="com.LongDa.service.Impl.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
</bean>
</beans>onent-scan base-package="com.kuang.service" /> <!--BookServiceImpl注入到IOC容器中--> <bean id="BookServiceImpl" class="com.kuang.service.BookServiceImpl"> <property name="bookMapper" ref="bookMapper"/> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入数据库连接池 --> <property name="dataSource" ref="dataSource" /> </bean></beans>
Spring就是一个大杂烩,一个容器!
springMVC层整合
1 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">
<!--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:ApplicationContext.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>
<!--encodingFilter 解决汉字乱码问题-->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--Session过期时间-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>
2 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">
<!-- 配置SpringMVC -->
<!-- 1.开启SpringMVC注解驱动 -->
<mvc:annotation-driven />
<!-- 2.静态资源默认servlet配置-->
<mvc:default-servlet-handler/>
<!-- 3.配置jsp 显示ViewResolver视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 4.扫描web相关的bean -->
<context:component-scan base-package="com.LongDa.controller" />
</beans>
3 Spring配置整合文件,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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="spring-dao.xml"/>
<import resource="spring-service.xml"/>
<import resource="spring-mvc.xml"/>
</beans>