SpringMVC

SpringMVC

任务一: SpringMVC基本应用

一 SpringMVC简介

1.1 MVC模式

​ MVC是软件工程中的一种软件架构模式,它是一种分离业务逻辑与显示界面的开发思想。

* M(model)模型:处理业务逻辑,封装实体

* V(view) 视图:展示内容

* C(controller)控制器:负责调度分发(1.接收请求、2.调用模型、3.转发到视图)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TZkpq3J8-1629201553697)(E:\MarkDown\拉勾笔记\MVC模式)]

1.2 SpringMVC概述

​ SpringMVC 是一种基于 Java 的实现 MVC 设计模式的轻量级 Web 框架,属于SpringFrameWork 的 后续产品,已经融合在 Spring Web Flow 中。

​ SpringMVC 已经成为目前最主流的MVC框架之一,并且随着Spring3.0 的发布,全面超越 Struts2, 成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S2l8T1Yh-1629201553700)(E:\MarkDown\拉勾笔记\SpringMVC概述)]

总结

​ SpringMVC的框架就是封装了原来Servlet中的共有行为;例如:参数封装,视图转发等。

1.3 SpringMVC快速入门

需求:客户端发起请求,服务器接收请求,执行逻辑并进行视图跳转。

步骤分析

1. 创建web项目,导入SpringMVC相关坐标
2. 配置SpringMVC前端控制器 DispathcerServlet
3. 编写Controller类和视图页面
4. 使用注解配置Controller类中业务方法的映射地址
5. 配置SpringMVC核心文件 spring-mvc.xml
1)创建web项目,导入SpringMVC相关坐标
<!-- 设置为web工程 -->
<packaging>war</packaging>
<dependencies>
    <!--springMVC坐标-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
    <!--servlet坐标-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <!--jsp坐标-->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
2)配置SpringMVC前端控制器DispathcerServlet
<?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">

    <!--springmvc的前端控制器: DispathcerServlet-->
    <servlet>
        <servlet-name>DispathcerServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--加载springmvc核心配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <!--在应用启动时,就完成Servlet的实例化及初始化操作-->
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DispathcerServlet</servlet-name>
        <!-- / 会匹配到所有的访问路径,但是不会匹配到像*.jsp这样的url /login /add /update-->
        <!-- / 和 /* 的区别-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
3)编写Controller类和视图页面

UserController.java

public class UserController {

    public String quick(){
        // 业务逻辑
        System.out.println("springmvc入门成功....");
        // 视图跳转
        return "/WEB-INF/pages/success.jsp";
    }

}

/WEB-INF/pages/ success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>springmvc入门成功</h3>
</body>
</html>
4)使用注解配置Controller类中业务方法的映射地址
@Controller
public class UserController {

    @RequestMapping("/quick")
    public String quick(){
        // 业务逻辑
        System.out.println("springmvc入门成功....");
        // 视图跳转
        return "/WEB-INF/pages/success.jsp";
    }
}
5)配置SpringMVC核心文件spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置IOC注解扫描-->
    <context:component-scan base-package="com.lagou.controller"/>

</beans>
1.4 web工程执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o2UDwnkQ-1629201553703)(E:\MarkDown\拉勾笔记\web工程执行流程)]

1.5 知识小结
* SpringMVC是对MVC设计模式的一种实现,属于轻量级的WEB框架。

* SpringMVC的开发步骤:
	1.创建web项目,导入SpringMVC相关坐标
	2.配置SpringMVC前端控制器 DispathcerServlet
	3.编写Controller类和视图页面
	4.使用注解配置Controller类中业务方法的映射地址
	5.配置SpringMVC核心文件 spring-mvc.xml

二 SpringMVC组件概述

2.1 SpringMVC的执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PRNG1Jsb-1629201553706)(E:\MarkDown\拉勾笔记\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将渲染后的视图响应响应用户。
2.2 SpringMVC组件解析
1. 前端控制器:DispatcherServlet
	用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。

2. 处理器映射器:HandlerMapping
	HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

3. 处理器适配器:HandlerAdapter
	通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

4. 处理器:Handler【**开发者编写**】
	它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到Handler。由Handler 对具体的用户请求进行处理。

5. 视图解析器:ViewResolver
	View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。

6. 视图:View 【**开发者编写**】
	SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

	***笔试题:springmvc中的三大组件是什么?
	处理器映射器:HandlerMapping、处理器适配器:HandlerAdapter、视图解析器:ViewResolver
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置IOC注解扫描-->
    <context:component-scan base-package="com.lagou"/>

    <!--配置处理器映射器-处理器适配器 进行了功能的增强:支持json的读写-->
    <mvc:annotation-driven/>

    <!--配置视图解析器: ViewResolver-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--success :解析逻辑视图名,解析成具体的物理文件地址 /WEB-INF/pages/success.jsp -->

        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>
2.3 SpringMVC注解解析
@Controller

​ SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用:

<!--配置注解扫描-->
<context:component-scan base-package="com.lagou.controller"/>
@RequestMapping
* 作用:
	用于建立请求 URL 和处理请求方法之间的对应关系

* 位置:
	1.类上:请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
		它出现的目的是为了使我们的URL可以按照模块化管理:
			用户模块
				/user/add
				/user/update
				/user/delete
					...
			账户模块
                /account/add
                /account/update
                /account/delete
	2.方法上:请求URL的第二级访问目录,和一级目录组成一个完整的 URL 路径。

* 属性:
	1.value:用于指定请求的URL。它和path属性的作用是一样的
	2.method:用来限定请求的方式
	3.params:用来限定请求参数的条件
	例如:params={"accountName"} 表示请求参数中必须有accountName
		pramss={"money!100"} 表示请求参数中money不能是100
2.4 知识小结
* SpringMVC的三大组件
	处理器映射器:HandlerMapping
	处理器适配器:HandlerAdapter
	视图解析器:View Resolver

* 开发者编写
	处理器:Handler
	视图:View

三 SpringMVC的请求

3.1 请求参数类型介绍

客户端请求参数的格式是: name=value&name=value……

服务器要获取请求的参数的时候要进行类型转换,有时还需要进行数据的封装

SpringMVC可以接收如下类型的参数:

​ 基本类型参数

​ 对象类型参数

​ 数组类型参数

​ 集合类型参数

3.2 获取基本类型参数

​ Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。并且能自 动做类型转换;自动的类型转换是指从String向其他类型的转换。

<a href="${pageContext.request.contextPath}/user/simpleParam?id=1&username=杰克">
基本类型
</a>
@RequestMapping("/simpleParam")
public String simpleParam(Integer id,String username) {
    System.out.println(id);
    System.out.println(username);
    return "success";
}
3.3 获取对象类型参数

​ Controller中的业务方法参数的POJO属性名与请求参数的name一致,参数值会自动映射匹配。

<%--form表单 该表单提交的请求类型为post类型--%>
<form action="${pageContext.request.contextPath}/user/pojoParam" method="post">
    编号: <input type="text" name="id">
    用户名: <input type="text" name="username">
    <input type="submit" value="对象类型参数">
</form>
public class User {
    
    private Integer id;
    private String username;
    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}
/**
 * 获取对象类型请求参数
 */
@RequestMapping("/pojoParam")
public String pojoParam(User user){
    System.out.println(user);
    return "success";
}
3.4 中文乱码过滤器

​ 当post请求时,数据会出现乱码,我们可以在web.xml中设置一个过滤器来进行编码的过滤。

<!--配置全局过滤的filter-->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filterclass>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>
3.5 获取数组类型参数

​ Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。

<%--演示获取数组类型请求参数--%>
<form action="${pageContext.request.contextPath}/user/arrayParam" method="post">
	编号: <input type="checkbox" name="ids" value="1">1<br>
	<input type="checkbox" name="ids" value="2">2<br>
	<input type="checkbox" name="ids" value="3">3<br>
	<input type="checkbox" name="ids" value="4">4<br>
	<input type="submit" value="数组类型参数">
</form>
/**
 * 获取数组类型请求参数
 */
@RequestMapping("/arrayParam")
public String arrayParam(Integer[] ids){
    System.out.println(Arrays.toString(ids));
    return "success";
}
3.6 获取集合(复杂)类型参数

​ 获得集合参数时,要将集合参数包装到一个POJO中才可以。

<%--演示获取集合类型请求参数--%>
<form action="${pageContext.request.contextPath}/user/queryParam" method="post">
    搜索关键字:
    		<input type="text" name="keyword"> <br>

    user对象:
    		<input type="text" name="user.id" placeholder="编号">
		    <input type="text" name="user.username" placeholder="姓名"><br>
    
    list集合:
    		第一个元素:
		    <input type="text" name="userList[0].id" placeholder="编号">
    		<input type="text" name="userList[0].username" placeholder="姓名"><br>

    		第二个元素:
            <input type="text" name="userList[1].id" placeholder="编号">
            <input type="text" name="userList[1].username" placeholder="姓名"><br>
    
    map集合:
    		第一个元素:
            <input type="text" name="userMap['u1'].id" placeholder="编号">
            <input type="text" name="userMap['u1'].username" placeholder="姓名"><br>
    
    		第二个元素:
            <input type="text" name="userMap['u2'].id" placeholder="编号">
            <input type="text" name="userMap['u2'].username" placeholder="姓名"><br>
    
    <input type="submit" value="复杂类型">
</form>
public class QueryVo {
    
    private String keyword;
    private User user;
    private List<User> userList;
    private Map<String,User> userMap;

    @Override
    public String toString() {
        return "QueryVo{" +
                "keyword='" + keyword + '\'' +
                ", user=" + user +
                ", userList=" + userList +
                ", userMap=" + userMap +
                '}';
    }

    public String getKeyword() {
        return keyword;
    }

    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

    public Map<String, User> getUserMap() {
        return userMap;
    }

    public void setUserMap(Map<String, User> userMap) {
        this.userMap = userMap;
    }
}
/**
 * 获取结合(复杂)类型请求参数
 */
@RequestMapping("/queryParam")
public String queryParam(QueryVo queryVo){
    System.out.println(queryVo);
    return "success";
}
3.7 自定义类型转换器

​ SpringMVC 默认已经提供了一些常用的类型转换器;例如:客户端提交的字符串转换成int型进行参数设置,日期格式类型要求为:yyyy/MM/dd 不然的话会报错,对于特有的行为,SpringMVC提供了自定义类型转换器方便开发者自定义处理。

<%--演示自定义类型转换器 : 错误的产生 2012/12/12--%>
<form action="${pageContext.request.contextPath}/user/converterParam" method="post">
    生日:<input type="text" name="birthday">
    <input type="submit" value="自定义类型转换器">
</form>
public class DateConverter implements Converter<String, Date> {

    // s 就是表单传递过来的请求参数 2012-12-12
    @Override
    public Date convert(String s) {

        // 将日期字符串转换成日期对象,进行返回
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = simpleDateFormat.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}
<!--配置处理器映射器-处理器适配器 进行了功能的增强:支持json的读写-->
<mvc:annotation-driven conversion-service="conversionService"/>

<!--自定义类型转换器配置-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">

    <property name="converters">
        <set>
            <bean class="com.lagou.converter.DateConverter"/>
        </set>
    </property>
</bean>
/**
 * 获取日期类型参数:(自定义类型转换器)
 */
@RequestMapping("/converterParam")
public String converterParam(Date birthday){
    System.out.println(birthday);
    return "success";
}
3.8 相关注解
@RequestParam

​ 当请求的参数name名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定

<%--演示@RequestParam--%>
<a href="${pageContext.request.contextPath}/user/findByPage?pageNo=2">
	分页查询
</a>
/**
 * 演示@RequestParam
 *
 * @RequestParam
 *      name: 匹配页面传递参数的名称
 *      defaultValue: 设置参数默认值
 *      required: 设置是否必须传递该参数,默认值为true,如果设置默认值,值自动改为false
 */
@RequestMapping("/findByPage")
public String findByPage(@RequestParam(name = "pageNo",defaultValue = "1",required = false) Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize){
    System.out.println(pageNum);	// 2
    System.out.println(pageSize);	// 5
    return "success";
}
@RequestHeader

获取请求头的数据。

/**
 * @RequestHeader注解的使用
 */
@RequestMapping("/requestHeader")
public String requestHead(@RequestHeader("cookie") String cookie){
    System.out.println(cookie);
    return "success";
}
@CookieValue

获取cookie中的数据。

/**
 * @CookieValue注解的使用
 */
@RequestMapping("/cookieValue")
public String cookieValue(@CookieValue("JSESSIONID") String jsessionId){
    System.out.println(jsessionId);
    return "success";
}
3.9 获取Servlet相关API

SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:

/**
 * 原始servletAPI的获取
 */
@RequestMapping("/servletAPI")
public String servletAPI(HttpServletRequest request, HttpServletResponse response, HttpSession session){
    System.out.println(request);
    System.out.println(response);
    System.out.println(session);
    return "succrss";
}

四 SpringMVC的响应

4.1 SpringMVC响应方式介绍

页面跳转

​ 1、返回字符串逻辑视图

​ 2、void原始ServletAPI

​ 3、ModelAndView

返回数据

​ 1、直接返回字符串数据

​ 2、将对象或集合转为json返回(任务二演示)

4.2 返回字符串逻辑视图

直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转到指定页面

@RequestMapping("/returnString")
public String returnString() {
    return "success";
}
4.3 void原始ServletAPI

我们可以通过request、response对象实现响应

/**
 * 通过原始servletAPI进行页面跳转
 */
@RequestMapping("/returnVoid")
public void returnVoid(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
    
    // 1.直接返回数据
    response.setContentType("text/html;charset=utf-8");
    response.getWriter().write("拉勾网");

    // 2.借助reques对象完成请求转发 一次请求
    //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);

    // 3.借助response对象完成重定向 两次请求 WEB-INF: 安全目录: 不允许外部请求直接访问该目录资源,只可以进行服务器内部转发
    //response.sendRedirect(request.getContextPath() + "/index.jsp");

}
4.4 转发和重定向

​ 企业开发我们一般使用返回字符串逻辑视图实现页面的跳转,这种方式其实就是请求转发。

我们也可以写成:forward转发

​ 如果用了forward:则路径必须写成实际视图url,不能写逻辑视图。它相当于:

request.getRequestDispatcher("url").forward(request,response)

​ 使用请求转发,既可以转发到jsp,也可以转发到其他的控制器方法。

/**
 * 演示forward关键字进行请求转发
 */
public String forward(Model model){

    // 还想在模型中设置一些值怎么做?
    model.addAttribute("username","拉勾招聘");

    // 使用请求转发,既可以转发到jsp,也可以转发到其他的控制器方法
    //return "forward:/product/findAll";
    return "forward:/WEB-INF/pages/success.jsp";
}


<body>
    <h3>success.... ${username}</h3>
</body>

Redirect重定向

​ 我们可以不写虚拟目录,springMVC框架会自动拼接,并且将Model中的数据拼接到url地址上

/**
 * 演示redirect关键字进行重定向
 *	当写了redirect关键字或者forward关键字,是不会再走视图解析器
 */
@RequestMapping("/redirect")
public String redirect(Model model){
    // 底层使用的还是request.setAttribute("username","拉勾教育")域范围:一次请求
    model.addAttribute("username","拉勾教育");
    
    return "redirect:/index.jsp";
}
4.5 ModelAndView
4.5.1 方式一

​ 在Controller中方法创建并返回ModelAndView对象,并且设置视图名称

/**
 * ModelAndView进行页面跳转:方式一
 */
@RequestMapping("/returnModelAndView")
public ModelAndView returnModelAndView(){
    /**
         * model: 模型: 作用封装存放数据
         * View: 视图: 用来展示数据
         */
    ModelAndView modelAndView = new ModelAndView();
    // 设置模型数据
    modelAndView.addObject("username","modelAndView方式一");

    // 设置视图名称 视图解析器解析 modelAndView 拼接前缀和后缀
    modelAndView.setViewName("success");

    return modelAndView;
}
4.5.2 方式二

​ 在Controller中方法形参上直接声明ModelAndView,无需在方法中自己创建,在方法中直接使用该 对象设置视图,同样可以跳转页面

/**
 * ModelAndView进行页面跳转:方式二
 */
@RequestMapping("/returnModelAndView2")
public ModelAndView returnModelAndView(ModelAndView modelAndView){
    /**
         * model: 模型: 作用封装存放数据
         * View: 视图: 用来展示数据
         */

    // 设置模型数据
    modelAndView.addObject("username","modelAndView方式二");

    // 设置视图名称 视图解析器解析 modelAndView 拼接前缀和后缀
    modelAndView.setViewName("success");

    return modelAndView;
}
4.6 @SessionAttributes

​ 如果在多个请求之间共用数据,则可以在控制器类上标注一个 @SessionAttributes,配置需要在 session中存放的数据范围,Spring MVC将存放在model中对应的数据暂存到 HttpSession 中。

注意:@SessionAttributes只能定义在类上

@Controller
@RequestMapping("/user")    // 一级访问目录
@SessionAttributes("username") // 向request域存入的key为username时,同步到session域中
public class UserController {
    
    /**
     * 演示forward关键字进行请求转发
     */
    @RequestMapping("/forward")
    public String forward(Model model){

        // 还想在模型中设置一些值怎么做?
        model.addAttribute("username","拉勾招聘");

        // 使用请求转发,既可以转发到jsp,也可以转发到其他的控制器方法
        //return "forward:/product/findAll";
        return "forward:/WEB-INF/pages/success.jsp";
    }

    /**
     * 演示@SessionAttribute的效果:多个请求之间共享数据
     */
    @RequestMapping("/returnString")
    public String returnString(){
        return "success";
    }
}
4.7 知识小结
* 页面跳转采用返回字符串逻辑视图
	1.forward转发
		可以通过Model向request域中设置数据
	2.redirect重定向
		直接写资源路径即可,虚拟目录springMVC框架自动完成拼接

* 数据存储到request域中
	Model model
		model.addAttribute("username", "子慕");

五 静态资源访问的开启

​ 当有静态资源需要加载时,比如jquery文件,通过谷歌开发者工具抓包发现,没有加载到jquery文 件,原因是SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是 /(缺省),代表对所有的 静态资源都进行处理操作,这样就不会执行Tomcat内置的DefaultServlet处理,我们可以通过以下两种 方式指定放行静态资源:

方式一

<!--方式一:放行指定静态资源 mapping:放行的映射路径  location:静态资源所在的目录-->
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/img/**" location="/img/"/>

方式二

<!--方式二:放行全部静态资源:在springmvc配置文件中开启DefaultServlet处理静态资源-->
<mvc:default-servlet-handler/>

任务二:springmvc进阶

一 ajax异步交互

​ Springmvc默认用MappingJackson2HttpMessageConverter对json数据进行转换,需要加入 jackson的包;同时使用 <mvc:annotation-driven />

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.8</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.0</version>
</dependency>
1.1 @RequestBody

​ 该注解用于Controller的方法的形参声明,当使用ajax提交并指定contentType为json形式时,通过 HttpMessageConverter接口转换为对应的POJO对象。

<script src="${pageContext.request.contextPath}/js/jquery-3.5.1.js"></script>

<%--ajax异步交互--%>
<button id="btn1">ajax异步提交</button>

<script>
    $("#btn1").click(function () {

        let url = '${pageContext.request.contextPath}/user/ajaxRequest';
        let data = '[{"id":1,"username":"张三"},{"id":2,"username":"李四"}]';

        $.ajax({
            type:'post',
            url:url,
            data:data,
            contentType : 'application/json;charset=utf-8',
            success:function (resp) {
                alert(JSON.stringify(resp));
            }
        });

    })

</script>
/**
 * ajax异步交互  [{"id":1,"username":"张三"},{"id":2,"username":"李四"}]
 */
@RequestMapping("/ajaxRequest")
public void ajaxRequest(@RequestBody List<User> list){
    System.out.println(list);
}
1.2 @ResponseBody

​ 该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端。

@RequestMapping("/ajaxRequest")
@ResponseBody
public List<User> ajaxRequest(@RequestBody List<User> list){
    System.out.println(list);
    return list;
}

二 RESTful

2.1 什么是RESTful

​ Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。

Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:

GET:读取(Read)

POST:新建(Create)

PUT:更新(Update)

DELETE:删除(Delete)

客户端请求原来风格URL地址RESTful风格URL地址
查询所有/user/findAllGET /user
根据ID查询/user/findById?id=1GET /user/{1}
新增/user/savePOST /user
修改/user/updatePUT /user
删除/user/delete?id=1DELETE /user/{1}
2.2 代码实现

@PathVariable

​ 用来接收RESTful风格请求地址中占位符的值

@RestController

​ RESTful风格多用于前后端分离项目开发,前端通过ajax与服务器进行异步交互,我们处理器通常回的是json数据所以使用@RestController来替代@Controller和@ResponseBody两个注解。

//@Controller
@RestController     // 组合注解: 组合@Controller + @ResponseBody
@RequestMapping("/restful")
public class RestFulController {

    /**
     * 根据id进行查询
     * localHost:8080/项目名/restful/user/2 + get请求方式
     */
    //@ResponseBody
    @GetMapping("/user/{id}")   //@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
    public String findById(@PathVariable Integer id){
        // 调用service方法完成id为2的这条记录的查询
        // 问题:findById中怎么才能获取restful编程风格中url里面占位符的值

        return "findById:" + id;
    }

    /**
     * 新增方法
     */
    @PostMapping("/user")   //@RequestMapping(value = "/user",method = RequestMethod.POST)
    public String post(){
        // 新增
        return "post";
    }

    /**
     * 更新方法
     */
    @PutMapping("/user")
    public String put(){
        // 更新操作
        return "put";
    }

    /**
     * 删除方法
     */
    @DeleteMapping("/user/{id}")
    public String delete(@PathVariable Integer id){
        // 删除操作
        return "delete" + id;
    }
}

三 文件上传

3.1 文件上传三要素

1、表单项 type=“file”

2、表单的提交方式 method=“POST”

3、表单的enctype属性是多部分表单形式 enctype=“multipart/form-data"

3.2 文件上传原理

1、当form表单修改为多部分表单时,request.getParameter()将失效。

2、当form表单的enctype取值为 application/x-www-form-urlencoded 时,

​ form表单的正文内容格式是: name=value&name=value

3、当form表单的enctype取值为 mutilpart/form-data 时,请求正文内容就变成多部分形式:

3.3 单文件上传
1)导入fileupload和io坐标
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>
2)spring-mvc.xml中配置文件上传解析器
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--设置文件上传最大值为5MB,5*1024*1024-->
    <property name="maxUploadSize" value="5242880"/>
    <!-- 设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240 -->
    <property name="maxInMemorySize" value="40960"/>
</bean>
3)编写文件上传代码
<%--编写一个满足文件山川三要素的表单
        1.表单提交方式必须是post
        2.表单的enctype属性必须要修改成multipart/form-data
        3.表单中必须要有文件上传项
--%>
<form action="${pageContext.request.contextPath}/fileupload" method="post" enctype="multipart/form-data">

    名称: <input type="text" name="username"><br>
    文件: <input type="file" name="filePic"><br>
         <input type="submit" value="单文件上传">
</form>
/**
 * 单文件上传
 */
@RequestMapping("/fileupload")
public String fileUpload(String username, MultipartFile filePic) throws IOException {

    // 获取表单的提交参数,完成文件上传
    System.out.println(username);

    // 获取原始文件上传名
    String originalFilename = filePic.getOriginalFilename();
    filePic.transferTo(new File("G:/upload/" + originalFilename));

    return "success";
}
3.4 多文件上传
<%--实现多文件上传--%>
<form action="${pageContext.request.contextPath}/filesupload" method="post" enctype="multipart/form-data">

    名称: <input type="text" name="username"><br>
    文件1: <input type="file" name="filePic"><br>
    文件2: <input type="file" name="filePic"><br>
    <input type="submit" value="多文件上传">
</form>
/**
 * 多文件上传
 */
@RequestMapping("/filesupload")
public String fileUpload(String username, MultipartFile[] filePic) throws IOException {

    // 获取表单的提交参数,完成文件上传
    System.out.println(username);

    // 获取原始文件上传名
    for (MultipartFile multipartFile : filePic) {
        String originalFilename = multipartFile.getOriginalFilename();
        multipartFile.transferTo(new File("G:/upload/" + originalFilename));
    }

    return "success";
}

四 异常处理

4.1 异常处理的思路

在Java中,对于异常的处理一般有两种方式:

​ 一种是当前方法捕获处理(try-catch),这种处理方式会造成业务代码和异常处理代码的耦合。

​ 另一种是自己不处理,而是抛给调用者处理(throws),调用者再抛给它的调用者,也就是一直向上抛。

​ 在这种方法的基础上,衍生出了SpringMVC的异常处理机制。

​ 系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mKRKgkyc-1629201553712)(E:\MarkDown\拉勾笔记\异常处理的思路)]

4.2 自定义异常处理器

步骤分析

1. 创建异常处理器类实现HandlerExceptionResolver
2. 配置异常处理器
3. 编写异常页面
4. 测试异常跳转
1)创建异常处理器类实现HandlerExceptionResolver
public class GlobalExceptionResolver implements HandlerExceptionResolver {

    /**
     * Exception e: 实际抛出的异常对象
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        // 具体异常处理 产生升异常后,跳转到一个最终的异常界面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("error",e.getMessage());
        modelAndView.setViewName("error");

        return modelAndView;
    }

}
2)配置异常处理器
@Controller
public class ExceptionController {}
<!--配置自定义的异常处理器-->
<bean id="globalExceptionResolver" class="com.lagou.exception.GlobalExceptionResolver"/>
3)编写异常页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>这是一个最终显示异常的页面</h3><br>
    ${error}
</body>
</html>
4)测试异常跳转
@GetMapping("/testException")
public String testException(){

    int i = 1/0;

    return "success";

}
4.3 web的处理异常机制

web.xml中配置

<!--处理404异常-->
<error-page>
    <error-code>404</error-code>
    <location>/404.jsp</location>
</error-page>
<!--处理500异常-->
<error-page>
    <error-code>500</error-code>
    <location>/500.jsp</location>
</error-page>

五 拦截器

5.1 拦截器(interceptor)的作用

​ Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理后处理

​ 将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。

5.2 拦截器和过滤器区别

关于interceptor和filter的区别,如下所示:

区别过滤器拦截器
使用范围是Servlet规范中的一部分,任何Java Web工程都可以使用是SpringMVC自己的,只有使用了SpringMVC框架的工程才能使用
拦截范围在url-pattern中配置了/*之后,可以对所有要访问的资源拦截只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会进行拦截的
5.3 快速入门

步骤分析

1. 创建拦截器类实现HandlerInterceptor接口
2. spring-mvc.xml配置拦截器
3. 测试拦截器的拦截效果
1)创建拦截器类实现HandlerInterceptor接口
public class MyInterceptor1 implements HandlerInterceptor {

    /**
     * preHandle: 在目标方法执行之前 进行拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");

        return true;
    }

    /**
     * postHandle: 在目标方法执行之后,视图对象返回之前,执行的方法
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    /**
     * afterCompletion: 在流程都执行完毕后,执行的方法
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}
2)配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--拦截器路径配置-->
        <mvc:mapping path="/**"/>   <!--对所有controller类里面的所有方法都进行拦截-->
        <!--自定义拦截器类-->
        <bean class="com.lagou.interceptor.MyInterceptor1"></bean>
    </mvc:interceptor>
</mvc:interceptors>
3)测试拦截器的拦截效果

编写Controller,发请求到controller,跳转页面

@Controller
public class TargetController {

    @RequestMapping("/target")
    public String targetMethod(){
        System.out.println("目标方法执行了....");
        return "success";
    }

}

编写jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>success.... ${username}</h3>

    <% System.out.println("视图执行了....");%>
</body>
</html>
5.4 拦截器链

​ 开发中拦截器可以单独使用,也可以同时使用多个拦截器形成一条拦截器链。开发步骤和单个拦截器是一样的,只不过注册的时候注册多个,注意这里注册的顺序就代表拦截器执行的顺序。

​ 同上,再编写一个MyInterceptor2操作,测试执行顺序:

<!--配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--拦截器路径配置-->
        <mvc:mapping path="/**"/>   <!--对所有controller类里面的所有方法都进行拦截-->
        <!--自定义拦截器类-->
        <bean class="com.lagou.interceptor.MyInterceptor1"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <!--拦截器路径配置-->
        <mvc:mapping path="/**"/>   <!--对所有controller类里面的所有方法都进行拦截-->
        <!--自定义拦截器类-->
        <bean class="com.lagou.interceptor.MyInterceptor2"></bean>
    </mvc:interceptor>
</mvc:interceptors>
5.5 知识小结

拦截器中的方法说明如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6NvxnWM-1629201553718)(E:\MarkDown\拉勾笔记\拦截器)]

任务三:SSM整合

1.1 需求和步骤分析

需求:使用ssm框架完成对 account 表的增删改查操作。

步骤分析

1. 准备数据库和表记录
2. 创建web项目
3. 编写mybatis在ssm环境中可以单独使用
4. 编写spring在ssm环境中可以单独使用
5. spring整合mybatis
6. 编写springMVC在ssm环境中可以单独使用
7. spring整合springMVC

1.2 环境搭建

1)准备数据库和表记录
CREATE TABLE `account` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(32) DEFAULT NULL,
    `money` double DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

insert into `account`(`id`,`name`,`money`) values (1,'tom',1000),(2,'jerry',1000);
2)创建web项目

1.3 编写mybatis在ssm环境中可以单独使用

需求:基于mybatis先来实现对account表的查询

1)相关坐标
<!--mybatis坐标-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.15</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>
2)Account实体
public class Account {

    private Integer id;
    private String name;
    private Double money;

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }
}
3)AccountDao接口
public interface AccountDao {

    /**
     * 查询所有账户
     */
    public List<Account> findAll();

}
4)AccountDao.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.lagou.dao.AccountDao">

    <!--查询所有用户-->
    <select id="findAll" resultType="account">
        select * from account
    </select>
    
</mapper>
5)mybatis核心配置文件

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?characterEncoding=utf8&useSSL=false
jdbc.username=root
jdbc.password=123456

SqlMapConfig.xml

<?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>

    <!--加载properties-->
    <properties resource="jdbc.properties"></properties>
    
    <!--配置别名-->
    <typeAliases>
        <package name="com.lagou.domain"/>
    </typeAliases>

    <!--运行环境配置 数据源-->
    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射-->
    <mappers>
        <package name="com.lagou.dao"/>
    </mappers>

</configuration>
6)测试代码
public class MybatisTest {

    @Test
    public void testMybatis() throws IOException {

        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();

        AccountDao mapper = sqlSession.getMapper(AccountDao.class);

        List<Account> all = mapper.findAll();

        for (Account account : all) {
            System.out.println(account);
        }

        sqlSession.close();

    }

}

1.4 编写spring在ssm环境中可以单独使用

1)相关坐标
<!--spring坐标-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.13</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.1.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.1.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.1.5.RELEASE</version>
</dependency>
2)AccountService接口
public interface AccountService {
    
    public List<Account> findAll();
    
}
3)AccountServiceImpl实现
@Service
public class AccountServiceImpl implements AccountService {

    /**
     * 测试spring在ssm环境中的单独使用
     */
    public List<Account> findAll() {
        System.out.println("findAll执行了....");
        return null;
    }

}
4)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"
       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">

    <!--配置IOC相关操作: 开启注解扫描-->
    <context:component-scan base-package="com.lagou.service"></context:component-scan>
    
</beans>
5)测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {

    @Autowired
    private AccountService accountService;

    @Test
    public void testSpring(){
        accountService.findAll();
    }

}

1.5 spring整合mybatis

1)整合思想

​ 将mybatis接口代理对象的创建权交给spring管理,我们就可以把dao的代理对象注入到service中, 此时也就完成了spring与mybatis的整合了。

2)导入整合包
<!--mybatis整合spring坐标-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>
3)spring配置文件管理mybatis

注意:此时可以将mybatis主配置文件删除。

<?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">

    <!--配置IOC相关操作: 开启注解扫描-->
    <context:component-scan base-package="com.lagou.service"></context:component-scan>

    <!--spring整合mybatis开始.................-->
    <context:property-placeholder location="classpath:jdbc.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>

    <!--sqlSessionFactory的创建权交给spring 产生sqlSession-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="com.lagou.domain"/>

        <!--引入加载mybatis核心配置文件,可以不用去加载-->
        <!--<property name="configLocation" value="classpath:SqlMapConfig.xml"/>-->
    </bean>

    <!--mapper映射扫描 MapperScannerConfigurer扫描该包下的所有接口,生成代理对象存到IOC容器中-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.lagou.dao"></property>
    </bean>
    <!--spring整合mybatis结束.................-->

</beans>
4)修改AccountServiceImpl
@Service
public class AccountServiceImpl implements AccountService {

    // 需要用到AccountDao的代理对象
    @Autowired
    private AccountDao accountDao;

    /**
     * 测试spring在ssm环境中的单独使用
     */
    public List<Account> findAll() {
        List<Account> all = accountDao.findAll();
        return all;
    }

}

1.6 编写springMVC在ssm环境中可以单独使用

需求:访问到controller里面的方法查询所有账户,并跳转到list.jsp页面进行列表展示

1)相关坐标
<!--springMVC坐标-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.5.RELEASE</version>
</dependency>
<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>jsp-api</artifactId>
    <version>2.2</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
2)导入页面资源
3)web.xml配置前端控制器DispathcerServlet
<?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_3_1.xsd"
         version="3.1">

    <!--前端控制器-->
    <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:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!--中文乱码过滤器: 解决post提交的乱码-->
    <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>
4)AccountController和 list.jsp
@Controller
@RequestMapping("/account")
public class AccountContriller {

    /**
     * 查询所有用户
     */
    @RequestMapping("/findAll")
    public String findAll(Model model){

        // 实现查询所有账户
        ArrayList<Account> list = new ArrayList<Account>();
        Account account = new Account();
        account.setId(1);
        account.setName("张三");
        account.setMoney(1000d);

        Account account2 = new Account();
        account2.setId(2);
        account2.setName("李四");
        account2.setMoney(2000d);

        list.add(account);
        list.add(account2);

        // 封装好的list存到model中
        model.addAttribute("list",list);
        return "list";
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head>
    <!-- 指定字符集 -->
    <meta charset="utf-8">
    <!-- 使用Edge最新的浏览器的渲染方式 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。
    width: 默认宽度与设备的宽度相同
    initial-scale: 初始的缩放比,为1:1 -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>账户列表</title>

    <!-- 1. 导入CSS的全局样式 -->
    <link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet">
    <!-- 2. jQuery导入,建议使用1.9以上的版本 -->
    <script src="${pageContext.request.contextPath}/js/jquery-2.1.0.min.js"></script>
    <!-- 3. 导入bootstrap的js文件 -->
    <script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
    <style type="text/css">
        td, th {
            text-align: center;
        }
    </style>
</head>
<body>
<div class="container">
  <div class="row">
      <h3 style="text-align: center">账户信息列表</h3>
      <div class="col-lg-2"></div>
      <div class="col-lg-8">

          <form action="${pageContext.request.contextPath}/account/deleteBatch" method="post" id="deleteBatchForm">
          <table border="1" class="table table-bordered table-hover">
              <tr class="success">
                  <th>
                      <input type="checkbox" id="checkAll">
                      <%--实现全选全不选效果--%>
                      <script>
                          $('#checkAll').click(function () {
                                $('input[name="ids"]').prop('checked',$(this).prop('checked'));
                          })
                      </script>

                  </th>
                  <th>编号</th>
                  <th>姓名</th>
                  <th>余额</th>
                  <th>操作</th>
              </tr>

              <c:forEach items="${list}" var="account">

              <tr>
                  <td>
                      <input type="checkbox" name="ids" value="${account.id}">
                  </td>
                  <td>${account.id}</td>
                  <td>${account.name}</td>
                  <td>${account.money}</td>
                  <td><a class="btn btn-default btn-sm" href="${pageContext.request.contextPath}/account/findById?id=${account.id}">修改</a>&nbsp;<a class="btn btn-default btn-sm" href="">删除</a></td>
              </tr>
              </c:forEach>

              <tr>
                  <td colspan="9" align="center">
                      <a class="btn btn-primary" href="${pageContext.request.contextPath}/add.jsp">添加账户</a>
                      <input class="btn btn-primary" type="button" value="删除选中" id="deleteBatchBtn">
                  </td>
              </tr>
          </table>
          </form>
      </div>
      <div class="col-lg-2"></div>
  </div>
</div>
</body>

<script>
    /*给删除选中按钮绑定点击事件*/
    $('#deleteBatchBtn').click(function () {
            if(confirm('您确定要删除吗')){
                if($('input[name=ids]:checked').length > 0){
                    /*提交表单*/
                    $('#deleteBatchForm').submit();
                }

            }else {
                alert('想啥呢,没事瞎操作啥')
            }


    })

</script>

</html>
5)springMVC核心配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--1.组件扫描: 只扫描controller-->
    <context:component-scan base-package="com.lagou.controller"></context:component-scan>

    <!--2.mvc注解增强: 处理器映射器及处理器适配器-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!--3.视图解析器-->
    <bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--4.静态资源放行-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>

</beans>

1.7 spring整合springMVC

1)整合思想

​ spring和springMVC其实根本就不用整合,本来就是一家。

​ 但是我们需要做到spring和web容器整合,让web容器启动的时候自动加载spring配置文件,web容器销毁的时候spring的ioc容器也销毁。

2)spring和web容器整合

ContextLoaderListener加载【掌握】

​ 可以使用spring-web包中的ContextLoaderListener监听器,可以监听servletContext容器的创建和销毁,来同时创建或销毁IOC容器。

web.xml配置

<!--配置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>
3)修改AccountController
@Controller
@RequestMapping("/account")
public class AccountContriller {

    @Autowired
    private AccountService accountService;

    /**
     * 查询所有用户
     */
    @RequestMapping("/findAll")
    public String findAll(Model model){

        // 实现查询所有账户
        List<Account> list = accountService.findAll();

        // 封装好的list存到model中
        model.addAttribute("list",list);
        return "list";
    }
}

1.8 spring配置声明式事务

1)spring配置文件加入声明式事务
<!--spring声明式事务-->
<!--1.事务管理器配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--2.开启事务注解支持-->
<tx:annotation-driven/>
@Service
@Transactional
public class AccountServiceImpl implements AccountService {
}
2)add.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head>
    <!-- 指定字符集 -->
    <meta charset="utf-8">
    <!-- 使用Edge最新的浏览器的渲染方式 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。
    width: 默认宽度与设备的宽度相同
    initial-scale: 初始的缩放比,为1:1 -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>添加用户</title>

    <!-- 1. 导入CSS的全局样式 -->
    <link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet">
    <!-- 2. jQuery导入,建议使用1.9以上的版本 -->
    <script src="${pageContext.request.contextPath}/js/jquery-2.1.0.min.js"></script>
    <!-- 3. 导入bootstrap的js文件 -->
    <script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <center><h3>添加账户</h3></center>
    <div class="row">
        <div class="col-lg-3"></div>
        <div class="col-lg-6">
            <form action="${pageContext.request.contextPath}/account/save" method="post">
                <div class="form-group">
                    <label for="name">姓名:</label>
                    <input type="text" class="form-control" id="name" name="name" placeholder="请输入姓名">
                </div>
                      <div class="form-group">
                    <label for="money">余额:</label>
                    <input type="text" class="form-control" id="money" name="money" placeholder="请输入余额">
                </div>

                <div class="form-group" style="text-align: center">
                    <input class="btn btn-primary" type="submit" value="提交" />
                    <input class="btn btn-default" type="reset" value="重置" />
                    <input class="btn btn-default" type="button" οnclick="history.go(-1)" value="返回" />
                </div>
            </form>
        </div>
        <div class="col-lg-3"></div>
    </div>
</div>
</body>
</html>
3)AccountController
/**
 * 添加账户
 */
@RequestMapping("/save")
public String save(Account account){
    accountService.save(account);
    // 跳转到findAll方法重新查询一次数据库进行数据的遍历展示
    return "redirect:/account/findAll";
}
4)AccountService接口和实现类
public void save(Account account);
@Service
@Transactional
public class AccountServiceImpl implements AccountService {

    // 需要用到AccountDao的代理对象
    @Autowired
    private AccountDao accountDao;

    /**
     * 账户添加
     */
    @Override
    public void save(Account account) {
        accountDao.save(account);
    }

}
5)AccountDao
public void save(Account account);
6)AccountDao.xml映射
<!--添加账户-->
<insert id="save" parameterType="account">
    insert into account(name,money) values (#{name},#{money})
</insert>

1.9 修改操作

1.9.1 数据回显
① AccountController
/**
 * 根据id查询账户信息,完成账户信息回显
 */
@RequestMapping("/findById")
public String findById(Integer id,Model model){

    Account account = accountService.findById(id);

    // 存到model中
    model.addAttribute("account",account);

    // 视图跳转
    return "update";
}
② AccountService接口和实现类
public Account findById(Integer id);
/**
 * 根据id查询账户信息
 */
@Override
public Account findById(Integer id) {
    return accountDao.findById(id);
}
③ AccountDao接口和映射文件
public Account findById(Integer id);
<!--根据id查询账户信息-->
<select id="findById" parameterType="int" resultType="account">
    select * from account where id = #{id}
</select>
④ update.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head>
    <!-- 指定字符集 -->
    <meta charset="utf-8">
    <!-- 使用Edge最新的浏览器的渲染方式 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。
    width: 默认宽度与设备的宽度相同
    initial-scale: 初始的缩放比,为1:1 -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>添加用户</title>

    <!-- 1. 导入CSS的全局样式 -->
    <link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet">
    <!-- 2. jQuery导入,建议使用1.9以上的版本 -->
    <script src="${pageContext.request.contextPath}/js/jquery-2.1.0.min.js"></script>
    <!-- 3. 导入bootstrap的js文件 -->
    <script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <center><h3>更新账户</h3></center>
    <div class="row">
        <div class="col-lg-3"></div>
        <div class="col-lg-6">
            <form action="${pageContext.request.contextPath}/account/update" method="post">
                <input type="hidden" name="id" value="${account.id}">
                <div class="form-group">
                    <label for="name">姓名:</label>
                    <input type="text" class="form-control" id="name" name="name" value="${account.name}" placeholder="请输入姓名">
                </div>
                <div class="form-group">
                    <label for="money">余额:</label>
                    <input type="text" class="form-control" id="money" name="money"  value="${account.money}" placeholder="请输入余额">
                </div>

                <div class="form-group" style="text-align: center">
                    <input class="btn btn-primary" type="submit" value="提交" />
                    <input class="btn btn-default" type="reset" value="重置" />
                    <input class="btn btn-default" type="button" οnclick="history.go(-1)" value="返回" />
                </div>
            </form>
        </div>
        <div class="col-lg-3"></div>
    </div>
</div>
</body>
</html>
1.9.2 账户更新
① AccountController
/**
 * 账户更新
 */
@RequestMapping("/update")
public String update(Account account){
    accountService.update(account);
    return "redirect:/account/findAll";
}
② AccountService接口和实现类
public void update(Account account);
/**
 * 更新账户
 */
@Override
public void update(Account account) {
    accountDao.update(account);
}
③ AccountDao接口和映射文件
public void update(Account account);
<!--更新账户-->
<update id="update" parameterType="account">
    update account set name = #{name},money = #{money} where id = #{id}
</update>

1.10 批量删除

1)list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head>
    <!-- 指定字符集 -->
    <meta charset="utf-8">
    <!-- 使用Edge最新的浏览器的渲染方式 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。
    width: 默认宽度与设备的宽度相同
    initial-scale: 初始的缩放比,为1:1 -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>账户列表</title>

    <!-- 1. 导入CSS的全局样式 -->
    <link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet">
    <!-- 2. jQuery导入,建议使用1.9以上的版本 -->
    <script src="${pageContext.request.contextPath}/js/jquery-2.1.0.min.js"></script>
    <!-- 3. 导入bootstrap的js文件 -->
    <script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
    <style type="text/css">
        td, th {
            text-align: center;
        }
    </style>
</head>
<body>
<div class="container">
  <div class="row">
      <h3 style="text-align: center">账户信息列表</h3>
      <div class="col-lg-2"></div>
      <div class="col-lg-8">

          <form action="${pageContext.request.contextPath}/account/deleteBatch" method="post" id="deleteBatchForm">
          <table border="1" class="table table-bordered table-hover">
              <tr class="success">
                  <th>
                      <input type="checkbox" id="checkAll">
                      <%--实现全选全不选效果--%>
                      <script>
                          $('#checkAll').click(function () {
                                $('input[name="ids"]').prop('checked',$(this).prop('checked'));
                          })
                      </script>

                  </th>
                  <th>编号</th>
                  <th>姓名</th>
                  <th>余额</th>
                  <th>操作</th>
              </tr>

              <c:forEach items="${list}" var="account">

              <tr>
                  <td>
                      <input type="checkbox" name="ids" value="${account.id}">
                  </td>
                  <td>${account.id}</td>
                  <td>${account.name}</td>
                  <td>${account.money}</td>
                  <td><a class="btn btn-default btn-sm" href="${pageContext.request.contextPath}/account/findById?id=${account.id}">修改</a>&nbsp;<a class="btn btn-default btn-sm" href="">删除</a></td>
              </tr>
              </c:forEach>

              <tr>
                  <td colspan="9" align="center">
                      <a class="btn btn-primary" href="${pageContext.request.contextPath}/add.jsp">添加账户</a>
                      <input class="btn btn-primary" type="button" value="删除选中" id="deleteBatchBtn">
                  </td>
              </tr>
          </table>
          </form>
      </div>
      <div class="col-lg-2"></div>
  </div>
</div>
</body>

<script>
    /*给删除选中按钮绑定点击事件*/
    $('#deleteBatchBtn').click(function () {
            if(confirm('您确定要删除吗')){
                if($('input[name=ids]:checked').length > 0){
                    /*提交表单*/
                    $('#deleteBatchForm').submit();
                }

            }else {
                alert('想啥呢,没事瞎操作啥')
            }


    })

</script>

</html>
2)AccountController
/**
 * 批量删除
 */
@RequestMapping("/deleteBatch")
public String deleteBatch(Integer[] ids){
    accountService.deleteBatch(ids);

    return "redirect:/account/findAll";
}
3)AccountService接口和实现类
public void deleteBatch(Integer[] ids);
/**
 * 批量删除
 */
@Override
public void deleteBatch(Integer[] ids) {
    accountDao.deleteBatch(ids);
}
4)AccountDao接口和映射文件
public void deleteBatch(Integer[] ids);
<!--批量删除-->
<delete id="deleteBatch" parameterType="int">
    delete from account
    <where>
        <foreach collection="array" open="id in(" close=")" separator="," item="id">
            #{id}
        </foreach>
    </where>
</delete>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值