SpringMVC
基于MVC开发模式的框架,用来优化控制器,是Spring的一员,也具备IOC和AOP
MVC是一种开发模式,它是模型视图控制器的简称,所有web应用都是基于MVC开发
M:模型层,包含实体类,业务逻辑层,数据访问层
V:视图层,html,JavaScript,vue
C:控制器,用来接收客户端的请求,并返回响应到客户端的组件,Servlet就是组件
分析web请求
DispatcherServlet要在web.xml文件中注册才可用
web请求执行流程 xxx.jsp<------>DispatcherServlet<------>SpringMVC的处理器是一个普通方法
<servlet>
<servlet-name>springmvc</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>
</servlet>
<!--设置简短访问名后缀-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
@RequestMapping注解用来映射服务器访问的路径
加在方法上,是为此方法注册一个可访问的名称(路径) /路径.action
加在类上,相当于是包名(虚拟路径) /虚拟路径/路径.action
@Controller//交给Spring创建对象
public class DemoAction {
/*
* action中所有的功能实现都是由方法来完成
* action方法的规范
* 1.访问权限public
* 2.方法的返回值任意
* 3.方法名称任意
* 4.方法可以无参
* 5.要用@RequestMapping注解来声明一个访问的路径名称
* */
@RequestMapping("/demo")
public String demo(){
System.out.println("服务器被访问");
return "main";//可以直接转到/admin/main.jsp页面上
}
}
此注解可以区分get请求和post请求
@Controller
public class ReqAction {
@RequestMapping(value = "/req",method = RequestMethod.GET)
public String req(){
System.out.println("get请求处理");
return "main";
}
@RequestMapping(value = "/req",method = RequestMethod.POST)
public String req1(){
System.out.println("post请求处理");
return "main";
}
}
五种数据提交方式优化
1.单个提交数据
页面:
<form action="${pageContext.request.contextPath}/one.action">
姓名:<input name="name"><br>
年龄:<input name="age"><br>
<input type="submit" value="提交">
</form>
action:
@RequestMapping("/one")
public String one(String name,int age){
System.out.println("名字是"+name+"年龄是"+age);
return "main";
}
2.对象封装提交数据
在提交请求中,保证请求参数的名称和实体类的变量名称一致,可以自动创建对象,提交数据,类型转换,封装到对象中
页面:
<form action="${pageContext.request.contextPath}/two.action">
姓名:<input name="uname"><br>
年龄:<input name="uage"><br>
<input type="submit" value="提交">
</form>
action:
@RequestMapping("/two")
public String two(Users u){
System.out.println(u);
return "main";
}
3.动态占位符提交
仅限于超链接或地址栏提交数据,一杠一值一杠一大括号,使用@PathVariable注解来解析
页面:
<a href="${pageContext.request.contextPath}/three/张三/22.action">动态提交</a>
action:
@RequestMapping("/three/{name}/{age}")
public String three(@PathVariable String name, @PathVariable int age){
System.out.println("名字是"+name+"年龄是"+age);
return "main";
}
4.映射名称不一致
提交请求参数与action方法的形参的名称不一致,使用@RequestParam注解来解析
页面:
<form action="${pageContext.request.contextPath}/four.action">
姓名:<input name="name"><br>
年龄:<input name="age"><br>
<input type="submit" value="提交">
</form>
action:
@RequestMapping("/four")
public String four(@RequestParam("name") String uname,@RequestParam("age") int uage){
System.out.println("名字是"+uname+",年龄是"+uage);
return "main";
}
5.手工提取数据
页面:
<form action="${pageContext.request.contextPath}/five.action" method="get">
姓名:<input name="name"><br>
年龄:<input name="age"><br>
<input type="submit" value="提交">
</form>
action:
@RequestMapping("/five")
public String five(HttpServletRequest request){
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
System.out.println("名字是"+name+"年龄是"+age);
return "main";
}
中文乱码解决方案
<filter>
<filter-name>encode</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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
action方法的返回值
1.String:客户端资源的地址,自动拼接前缀和后缀,可以屏蔽自动拼接字符串,指定返回的路径
2.Object:返回json格式的对象,自动将对象或集合转为json,使用json工具进行转换必须要添加依赖,用于ajax请求
3.void:无返回值,用于ajax请求
4.8种基本类型,用于ajax请求
5.ModelAndView:返回数据和视图对象
四种转发方式请求转发和重定向转发
不改变网址的情况使用请求转发
改变网址的情况使用重定向转发
页面代码:
<a href="${pageContext.request.contextPath}/one.action">1.请求转发页面</a><br>
<a href="${pageContext.request.contextPath}/two.action">2.请求转发action</a><br>
<a href="${pageContext.request.contextPath}/three.action">3.重定向页面</a><br>
<a href="${pageContext.request.contextPath}/four.action">4.重定向action</a><br>
<a href="${pageContext.request.contextPath}/five.action">5.请求转发到login</a><br>
<a href="${pageContext.request.contextPath}/six.action">6.重定向转发到login</a><br>
action代码:
@Controller
public class JumpAction {
@RequestMapping("/one")
public String one (){
System.out.println("这是请求转发页面");
return "main";//默认是请求转发,用视图解析器拼接前缀后缀进行页面跳转
}
@RequestMapping("/two")
public String two (){
System.out.println("这是请求转发action");
//forward: 这个forward可以屏蔽视图解析器前缀和后缀的拼接,实现请求转发跳转
return "forward:/other.action";
}
@RequestMapping("/three")
public String three (){
System.out.println("这是重定向页面");
//redirect: 这个redirect可以屏蔽视图解析器前缀和后缀的拼接,实现重定向跳转
return "redirect:/admin/main.jsp";
}
@RequestMapping("/four")
public String four (){
System.out.println("这是重定向action");
//redirect: 这个redirect可以屏蔽视图解析器前缀和后缀的拼接,实现重定向跳转
return "redirect:/other.action";
}
@RequestMapping("/five")
public String five(){
return "forward:/fore/login.jsp";
}
@RequestMapping("/six")
public String six(){
return "redirect:/fore/login.jsp";
}
}
SpringMVC默认的参数类型
1.HttpServletRequest
2.HttpServletResponse
3.HttpSession
4.Model
5.Map
6.ModelMap
Map,Model,ModelMap和request一样使用请求作用域进行传递,所以必须是请求转发
页面:
requestUsers:${requestUsers}<br>
sessionUsers:${sessionUsers}<br>
modelUsers:${modelUsers}<br>
mapUsers:${mapUsers}<br>
modelmapUsers:${modelmapUsers}<br>
从index.jsp的数据:${param.name}
action:
@RequestMapping("/data")
public String data(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model,
Map map,
ModelMap modelMap){
Users u = new Users("张三",22);
request.setAttribute("requestUsers",u);
session.setAttribute("sessionUsers",u);
model.addAttribute("modelUsers",u);
map.put("mapUsers",u);
modelMap.addAttribute("modelmapUsers",u);
return "main";
}
日期的处理
1.日期的提交处理
A.单个日期处理
使用@DateTimeFormat注解,必须搭配springmvc.xml文件中的<mvc:annotationdriven>标签
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
@RequestMapping("/mydate")
public String mydate(@DateTimeFormat(pattern = "yyyy-MM-dd") Date mydate){
System.out.println(sf.format(mydate));
return "show";
}
B.类中全局日期处理
使用InitBinder注解
@InitBinder
public void Init(WebDataBinder dataBinder){
dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sf,true));
}
2.日期的显示处理
在页面上显示好看的日期,必须使用JSTL,要在pom文件添加依赖
页面:
<a href="${pageContext.request.contextPath}/list.action">显示集合中对象的日期成员</a>
action页面:
@RequestMapping("/list")
public String list(HttpServletRequest request) throws ParseException {
Student stu1 = new Student("张三",sf.parse("2000-01-01"));
Student stu2 = new Student("李四",sf.parse("2000-02-01"));
Student stu3 = new Student("王五",sf.parse("2000-03-01"));
List<Student> list = new ArrayList<>();
list.add(stu1);
list.add(stu2);
list.add(stu3);
request.setAttribute("list",list);
return "show";
}
jsp页面:
<%--导入jstl核心标签库--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--导入jstl格式化标签库--%>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<c:forEach items="${list}" var="stu">
<tr>
<td>${stu.name}</td>
<td><ftm:formatDate value="${stu.birthday}" pattern="yyyy-MM-dd"></ftm:formatDate> </td>
</tr>
</c:forEach>
资源在WEB-INF目录
此目录下的动态资源不可直接访问,只能通过请求转发的方式进行访问
springmvc.xml:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
action:
@Controller
public class webinfAction {
@RequestMapping("/showindex")
public String showindex(){
return "index";
}
@RequestMapping("/showmain")
public String showmain(){
return "main";
}
}
SpringMVC拦截器
针对请求和响应进行的额外处理,在请求和响应的过程中添加预处理,后处理和最终处理
1)preHandle():在请求被处理之前进行操作,预处理
该方法在处理器方法执行之前执行。其返回值为boolean,若为true,则紧接着会执行处理器方法,
且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。2)postHandle():在请求被处理之后,但结果还没有渲染前进行操作,可以改变响应结果,后处理
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。
由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,
所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。3)afterCompletion:所有的请求响应结束后执行善后工作,清理对象,关闭资源,最终处理
当preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。
即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。
afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据等。
拦截器实现的两种方式
1)继承HandlerInterceptorAdapter的父类
2)实现HandlerInterceptor接口,实现的接口,推荐使用实现接口的方式
拦截器功能实现
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//是否登陆过的判断
if (request.getSession().getAttribute("users") == null){
//==null就是没登陆过,转回登陆页面给出提示
request.setAttribute("msg","您还没有登陆过");
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
return false;
}
return true;//放行
}
}
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--映射要拦截的请求-->
<mvc:mapping path="/**"/>
<!--设置放行的请求-->
<mvc:exclude-mapping path="/showlogin"/>
<mvc:exclude-mapping path="/login"/>
<mvc:exclude-mapping path="/error"/>
<!--配置拦截器实现功能的类-->
<bean class="com.lv.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
SSM整合项目:
0)建库,建表
1)新建Maven项目,选择webapp模板
2)修改目录
3)修改pom.xml文件
4)添加jdbc.properties属性文件
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmuser?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&allowMultiQueries=true
jdbc.username=root
jdbc.password=root
5)添加SqlMapConfig.xml文件(使用模板)
<!--设置日志输出语句,显示相应操作的sql语名-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
6)添加applicationContext_mapper.xml文件(数据访问层的核心配置文件)
<!--读取属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置SqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"></property>
<!--配置SqlMapConfig.xml核心配置-->
<property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
<!--注册实体类-->
<property name="typeAliasesPackage" value="com.lv.pojo"></property>
</bean>
<!--注册mapper.xml文件-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.lv.mapper"></property>
</bean>
7)添加applicationContext_service.xml文件(业务逻辑层的核心配置文件)
<!--添加包扫描-->
<context:component-scan base-package="com.lv.service.impl"></context:component-scan>
<!--添加事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--一定要配置数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务切面-->
<tx:advice id="myadvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*select*" read-only="true"/>
<tx:method name="*find*" read-only="true"/>
<tx:method name="*serach*" read-only="true"/>
<tx:method name="*get*" read-only="true"/>
<tx:method name="*insert*" propagation="REQUIRED"/>
<tx:method name="*add*" propagation="REQUIRED"/>
<tx:method name="*create*" propagation="REQUIRED"/>
<tx:method name="*set*" propagation="REQUIRED"/>
<tx:method name="*update*" propagation="REQUIRED"/>
<tx:method name="*delete*" propagation="REQUIRED"/>
<tx:method name="*drop*" propagation="REQUIRED"/>
<tx:method name="*remove*" propagation="REQUIRED"/>
<tx:method name="*clear*" propagation="REQUIRED"/>
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!--配置切入点+绑定-->
<aop:config>
<aop:pointcut id="mycut" expression="execution(* com.lv.service.impl.*.*(..))"/>
<aop:advisor advice-ref="myadvice" pointcut-ref="mycut"></aop:advisor>
</aop:config>
8)添加spirngmvc.xml文件
<!--添加包扫描-->
<context:component-scan base-package="com.lv.controller"></context:component-scan>
<!--添加注解驱动-->
<mvc:annotation-driven></mvc:annotation-driven>
9)删除web.xml文件,新建,改名,设置中文编码,并注册spirngmvc框架,并注册Spring框架
<!--添加中文编码过滤器-->
<filter>
<filter-name>encode</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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--注册SpringMVC框架-->
<servlet>
<servlet-name>springmvc</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>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--注册Spring框架,目的启动spring容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext_*.xml</param-value>
</context-param>
10)新建实体类user
11)新建UserMapper.java接口
public interface UserMapper {
List<User> selectUserPage(@Param("userName")String userName,
@Param("userSex") String userSex,
@Param("startRow") int startRow); //起始行的值
int createUser(User user);
int deleteUserById(String userId);
int getRowCount(@Param("userName") String userName,@Param("userSex") String userSex);
int updateUserById(String userId);
}
12)新建UserMapper.xml实现增删查所有功能
<mapper namespace="com.lv.mapper.UserMapper">
<!--映射-->
<resultMap id="usermap" type="user">
<id property="userId" column="user_id"></id>
<result property="cardType" column="card_type"></result>
<result property="cardNo" column="card_no"></result>
<result property="userName" column="user_name"></result>
<result property="userSex" column="user_sex"></result>
<result property="userAge" column="user_age"></result>
<result property="userRole" column="user_role"></result>
</resultMap>
<!--定义全部列名-->
<sql id="allColumns">
user_id,card_type,card_no,user_name,user_sex,user_age,user_role
</sql>
<!--分页功能查询-->
<select id="selectUserPage" resultMap="usermap">
select <include refid="allColumns"></include>
from user
<where>
<if test="userName != null and userName != ''">
and user_name like concat('%',#{userName},'%')
</if>
<if test="userSex != null and userSex != ''">
and user_sex = #{userSex}
</if>
</where>
limit #{startRow},5
</select>
<!--增加功能-->
<insert id="createUser" parameterType="user">
insert into user values(#{userId},#{cardType},#{cardNo},#{userName},#{userSex},#{userAge},#{userRole})
</insert>
<!--删除功能-->
<delete id="deleteUserById" parameterType="String">
delete from user where user_id = #{userId}
</delete>
<!--获取总行数-->
<select id="getRowCount" resultType="int">
select count(*) from user
<where>
<if test="userName != null and userName != ''">
and user_name like concat('%',#{userName},'%')
</if>
<if test="userSex != null and userSex != ''">
and user_sex = #{userSex}
</if>
</where>
</select>
<!--更新用户-->
<update id="updateUserById" parameterType="String">
update user set
<where>
<if test="cardType != null and cardType != ''">
and card_type = #{cardType}),
</if>
<if test="cardNo != null and cardNo != ''">
and card_no = #{cardNo},
</if>
<if test="userName != null and userName != ''">
and user_name =#{userName},
</if>
<if test="userSex != null and userSex != ''">
and user_sex = #{userSex},
</if>
<if test="userAge != null and userAge != ''">
and user_age = #{userAge},
</if>
<if test="userRole != null and userRole != ''">
and user_role = #{userRole}
</if>
</where>
where user_id = #{userId}
</update>
</mapper>
13)新建service接口和实现类
UserService接口:
public interface UserService {
List<User> selectUserPage(String userName, String userSex, int startRow); //起始行的值
int createUser(User user);
int deleteUserById(String userId);
int getRowCount(String userName,String userSex);
int updateUserById(String userId);
}
UserServiceImpl实现类:
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public List<User> selectUserPage(String userName, String userSex, int startRow) {
return userMapper.selectUserPage(userName,userSex,startRow);
}
@Override
public int createUser(User user) {
return userMapper.createUser(user);
}
@Override
public int deleteUserById(String userId) {
return userMapper.deleteUserById(userId);
}
@Override
public int getRowCount(String userName, String userSex) {
return userMapper.getRowCount(userName,userSex);
}
@Override
public int updateUserById(String userId) {
return userMapper.updateUserById(userId);
}
}
14)新建测试类,完成所有功能的测试
@RunWith(SpringJUnit4ClassRunner.class)//启动spring容器
@ContextConfiguration(locations = {"classpath:applicationContext_mapper.xml","classpath:applicationContext_service.xml"})
public class Mytest {
@Autowired
UserService userService;
@Test
public void testselectUserPage(){
List<User> list = userService.selectUserPage("三","男",0);
list.forEach(user -> System.out.println(user));
}
@Test
public void testdeleteUserById(){
int num = userService.deleteUserById("15968162087363060");
System.out.println(num);
}
@Test
public void testgetRowCount(){
int num = userService.getRowCount(null,"男");
System.out.println(num);
}
@Test
public void testcreateUser(){
User u = new User("12345678912345678","身份证","543215432154321543","老八","女","28","公务员");
int num = userService.createUser(u);
System.out.println(num);
}
}
15)新建控制器,完成所有功能
@CrossOrigin //在服务器端支持跨域访问
@RestController //如果本类全是ajax请求使用此注解,@ResponseBody就可以不写
@RequestMapping("/user")
public class UserController {
@Autowired
//业务逻辑层的对象
UserService userService;
public static final int PAGE_SIZE = 5;
@RequestMapping("/selectUserPage")
public List<User> selectUserPage(String userName,String userSex,Integer page){
//根据页码计算起始行
int startRow = 0;
if (page != null){
startRow = (page - 1 )*PAGE_SIZE;
}
return userService.selectUserPage(userName,userSex,startRow);
}
@RequestMapping("/getRowCount")
public int getRowCount(String userName,String userSex){
return userService.getRowCount(userName,userSex);
}
@RequestMapping("/deleteUserById")
public int deleteUserById(String userId){
return userService.deleteUserById(userId);
}
@RequestMapping("/createUser")
public int createUser(User user){
String userId = System.currentTimeMillis() + "";
user.setUserId(userId);
return userService.createUser(user);
}
}
16)浏览器测试功能