目录
目录
1. 简介
1、什么是MVC
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
M:Model,模型层,指工程中的 JavaBean,作用是用于存储数据以及能处理用户请求的业务逻辑
JavaBean分为两类:
-
一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
-
一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的 html 或 jsp 等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的 servlet,作用是 接收请求 和 响应浏览器。根据视图提出的请求,判断将请求和数据交给哪个模型处理,处理后的有关结果交给哪个视图更新显示
MVC的工作流程: 用户通过 视图层 发送请求到服务器,在服务器中请求被 Controller 接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的 View 视图,渲染数据后最终响应给浏览器。
2、什么是SpringMVC
SpringMVC是Spring的一个后续产品,是Spring的一个子项目。
SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
-
发送请求到DispatcherServlet(前端控制器)
-
DispatcherServlet调用HandlerMapping查找 Handler,可以根据xml配置、注解进行查找
-
HandlerMapping向DispatcherServlet返回一个处理器执行链,处理器执行链HandlerExecutionChain,HandlerExecutionChain中包括拦截器HandlerInceptor,Handler(处理器)
-
DispatcherServlet将处理器执行链HandlerExecutionChain交给处理器适配器HandlerAdapter
-
处理器适配器HandlerAdapter去执行Handler(处理器)
-
Handler(处理器)返回ModelAndView( 模型和视图)
-
处理器适配器HandlerAdapter将ModelAndView( 模型和视图)返回给DispatcherServlet
-
DispatcherServlet调用ViewResolver(视图解析器)
-
ViewResolver(视图解析器)返回处理后的view
-
DispatcherServlet进行视图渲染,视图渲染将模型数据(在ModelAndView对象中)填充到request域
-
DispatcherServlet向浏览器返回相应结果
3、SpringMVC 的特点
-
Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
-
基于原生的Servlet,通过功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理
-
表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
-
代码清新简洁,大幅度提升开发效率
-
内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
-
性能卓著,尤其适合现代大型、超大型互联网项目要求
4、前期准备
-
PostMan
官网下载: Download Postman | Get Started for Free
postman是一款强大网页调试工具的客户端,postman为用户提供强大的Web API & HTTP请求调试功能。
-
idea
-
tomcat服务器
安装教程:Tomcat安装步骤及详细配置教程(2022最新版)_tomcat安装及配置教程_Java程序员-张凯的博客-CSDN博客
2. 项目搭建
2.1 创建maven项目
2.2 导包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- <artifactId>springmvc-preparing</artifactId>-->
<artifactId>library-springmvc</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--Junit 单元测试框架 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--Servlet - JSP spring开发web容器-->
<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.1</version>
<scope>provided</scope>
</dependency>
<!-- jstl包,使用EL表达式 ${}}-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.24</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.20</version>
</dependency>
<!-- lombok 自动生成getter、setter、toString、equals等方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- json数据 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
</dependencies>
<!--xml或properties配置文件要放在resources目录下才能被找到,
所以需要将src/main/java目录下的资源过滤开启,在pom.xml中的build标签里添加以下配置 -->
<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>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
2.3 springmvc开发步骤
1)DispatcherServlet (前端控制器)
web.xml
<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">
<welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list>
<!-- DispatcherServlet -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<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) ViewResolver(视图解析器)
负责将处理结果生成 View 视图 ViewResolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址 再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户
xml配置⽂件配置controller扫描,配置springmvc三⼤件
<?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">
<!-- 1.开启SpringMVC注解驱动 -->
<mvc:annotation-driven />
<!-- 2.配置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>
<!-- 3.扫描 web 相关的bean -->
<context:component-scan base-package="com.ssm.controller" />
</beans>
3)开发处理具体业务逻辑的Handler
(@Controller、 @RequestMapping)
package com.ssm.controller;
import com.ssm.pojo.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.List;
@Controller
public class TestController {
@RequestMapping("/hello1")
@ResponseBody //将数据作为返回值显示到界面
public String sayHello(){
return "hello1";
}
// 返回html标签渲染
@RequestMapping("/hello2")
@ResponseBody
public String sayHello2(){
return "<h1>hello2</h1>";
}
//返回一个对象数据 --->json格式
@RequestMapping("/book/show")
@ResponseBody
public Book show(){
return new Book(1,"数据库",41);
}
//返回多个json对象数据
@RequestMapping("/book/show2")
@ResponseBody
public List<Book> show2(){
List<Book> books = new ArrayList<Book>();
books.add(new Book(1,"数据库",41));
books.add(new Book(2,"计网",20));
books.add(new Book(3,"java",31));
return books;
}
// 前端接收数据 -->返回的“接收成功” 乱码 / 请求的key必须为likes!!
@RequestMapping(value = "/book/save",produces = "text/plain;charset=utf-8")
@ResponseBody
public String getParam(String[] likes){
for (String like : likes) {
System.out.println(like.toString());
}
return "接收成功";
}
//接收json格式的数据
@RequestMapping(value = "/book/save2",produces = "text/plain;charset=utf-8")
@ResponseBody
public String getJsonParam(@RequestBody List<Book> books){
for (Book book : books) {
System.out.println(book.toString());
}
return "Json数据接收成功";
}
// key名不同
@RequestMapping(value="/book/save3",produces = "text/plain;charset=utf-8"))
@ResponseBody
public String save3(@RequestParam("name") String username){//name是前端请求的参数名,username是接收的参数名
System.out.println(username);
return "key名不同的参数接收成功";
}
// 跳转到page1.jsp文件
@RequestMapping("/page1")
public String toPage(){
return "page1";
}
}
(1)mvc:view-controller标签
如果发送的请求不想通过controller,只想直接地跳转到目标页面,这时候就可以使用mvc:view-controller标签 在springmvc配置文件中配置:
<mvc:view-controller path="/hello" view-name="hello"></mvc:view-controller>
-
path=”/hello” 就是你访问的路径(相当于RequestMapping(“/hello”))
-
view-name=”hello”是你所要的视图(如hello.jsp,相当于return “hello”) 配置了这个后对于/hello请求,就会直接交给dispatcherServlet,然后使用ViewResolver进行解析。 相当于以下代码:
@RequestMapping(value="/hello")
public String hello(){
System.out.println("hello");
return "hello";
}
注意:
-
使用了这个标签后必须配置
<mvc:annotation-driven />
,否则会造成所有的@Controller注解无法解析,导致404错误。 -
如果请求存在处理器,则这个标签对应的请求处理将不起作用。因为请求是先去找处理器处理,如果找不到才会去找这个标签配置。
(2)转发和重定向
servlet转发重定向
request.getRequestDispatcher(String path).forward(ServletRequest request, ServletResponse response)
response.sendRedirect(String location)
Springmvc:
转发:在返回的字符串前面加上 “forward:/路径地址”。
重定向:在返回字符串的前面加上 “redirect:/路径地址”。
-
转发
@RequestMapping("/hello")
public String toHello(){
return "forward:/hello";//转发
}
-
重定向
@RequestMapping("/hello")
public String toHello(){
return "redirect:/hello";//重定向
}
-
转发重定向不同点
转发:是服务器内部的跳转,浏览器的地址栏不会发生变化。从一个页面到另一个页面的跳转还是同一个请求,也即是只有一个请求响应。可以通过request域来传递对象。 重定向:是浏览器自动发起对跳转目标的请求,浏览器的地址栏会发生变化。从一个页面到另一个页面的跳转是不同的请求,也即是有两个或两个以上的不同的请求的响应。无法通过request域来传递对象。
(3)中文乱码问题
-
返回值出现乱码
@RequestMapping(value = "/book/save",produces = "text/plain;charset=utf-8")//返回文本内容 @RequestMapping(value = "/book",produces = "application/json;charset=utf-8")//返回json格式
-
接收参数出现乱码
web.xml中加上:
<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>
4)配置tomcat并启动
2.4 注解
@RequestMapping
在Spring MVC 中使用 @RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置的映射作用一致。
<servlet>
<servlet-name>servletName</servlet-name>
<servlet-class>ServletClass</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletName</servlet-name>
<url-pattern>url</url-pattern>
</servlet-mapping>
@ResponseBody
1、概念 注解 @ResponseBody,使用在控制层(controller)的方法上。
2、作用 将方法的返回值,以特定的格式写入到 response 的body区域,进而将数据返回给客户端。
当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象。 如果返回值是字符串,那么直接将字符串写到客户端;如果是一个对象,会将对象转化为json串,然后写到客户端。
3、原理 控制层方法的返回值是如何转化为json格式的字符串的?其实是通过HttpMessageConverter中的方法实现的,它本是一个接口,在其实现类完成转换。如果是bean对象,会调用对象的getXXX()方法获取属性值并且以键值对的形式进行封装,进而转化为json串。如果是map集合,采用get(key)方式获取value值,然后进行封装。
@RequestParam
将 请求参数 绑定到你控制器的方法参数上(是springmvc中接收普通参数的注解)
@RequestBody
@RequestBody主要用来 接收前端 传递给后端的 json字符串 中的数据的(请求体中的数据的)
@Pathvariable
@Pathvariable映射URL绑定的占位符,将URL中的占位符参数绑定到控制器的方法进行入参时,URL中{xxx}占位符可以通过@Pathvariable(“XXX”)进行绑定。一般是在get请求中使用。
@Controller
使用注解前需要打开注解扫描
<context:component-scan base-package="com.ssm.controller"/>
以前在编写Controller方法的时候,需要开发者自定义一个Controller类实现Controller接口,实现handleRequest方法返回ModelAndView。并且需要在Spring配置文件中配置Handle,将某个接口与自定义Controller类做映射。
这么做有个复杂的地方在于,一个自定义的Controller类智能处理一个单一请求。而在采用@Contoller注解的方式,可以使接口的定义更加简单,将@Controller标记在某个类上,配合@RequestMapping注解,可以在一个类中定义多个接口,这样使用起来更加灵活。
被@Controller标记的类实际上就是个SpringMVC Controller对象,它是一个控制器类,而@Contoller注解在org.springframework.stereotype包下。其中被@RequestMapping标记的方法会被分发处理器扫描识别,将不同的请求分发到对应的接口上。
@Service @Repository
首先了解一下IOC操作Bean管理,bean管理是指(1)spring创建对象 (2)spring注入属性。当我们在将一个类上标注@Service或者@Controller或@Component 或 @Repository注解之后,spring的组件扫描就会自动发现它,并且会将其初始化为spring应用上下文中的bean。 而且初始化是根据无参构造函数。
@Autowired
@Autowired 可以标注在属性上、方法上 和 构造器上,来完成自动装配。默认是根据属性类型,spring自动将匹配到的属性值进行注入,然后就可以使用这个属性(对Springboot02WebApplicationTests类来说)autoWiredBean对象的方法。
@Autowired //自动注入 省去set private BookMapper bookMapper;
@Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常
@Qualifier限定描述符除了能根据名字进行注入,更能进行更细粒度的控制如何选择候选者
多个Bean的时候使用@Qualifier
3. http 请求方式
3.1 常见请求方式
在@RequestMapping注解请求中如果未指定请求类型,则默认为GET类型请求或POST类型请求。
常见请求方式的有5种,分别是 GET、HEAD, POST、PUT、 DELETE :
-
GET 是最常见的方法,用于获取资源,常用于向服务器查询某些信息。打开网页一般都是用GET方法,因为要从 Web 服务器获取信息
-
HEAD:类似于 GET请求,只不过返回的响应中没有具体的内容,用于获取报头。
-
POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件), 数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或对已有资源的修改。
-
PUT:从客户端向服务器传送的数据取代指定文档的内容。
-
DELETE:请求服务器删除指定的页面。
最常见的HTTP请求方法是GET 和 POST。GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。
@Controller
@RequestMapping(value = "/book",produces = "text/plain;charset=utf-8")
public class TestContrller2 {
// 请求方式 : get post put delete
// @RequestMapping(value = "/book", method = RequestMethod.GET)
@GetMapping(value = "")
@ResponseBody
public String showBook(){
return "get";
}
// @RequestMapping(value = "/book")
@PostMapping("")
@ResponseBody
public String addBook(){
return "post";
}
// @RequestMapping(value = "/book")
@PutMapping("")
@ResponseBody
public String updateBook(){
return "put";
}
// @RequestMapping(value = "/book")
@DeleteMapping("")
@ResponseBody
public String delBook(){
return "delete";
}
}
参数:
来自路径上的参数:一般用get请求方式,@PathVariable()声明参数是来自路径的
@Controller
@RequestMapping(value = "/book",produces = "application/json;charset=utf-8")
public class BookController {
/* 1、get 取,是查询数据,对应select操作
2、post 贴,常用于修改数据,对应update操作
3、put 放,常用于新增数据,对应insert操作
4、delete 删,是删除数据,对应delete操作 */
@GetMapping(value = "/show")
@ResponseBody
public List<Book> showAllBook(){
List<Book> bookList = new ArrayList<>();
bookList.add(new Book(1,"数据库",20.1));
bookList.add(new Book(2,"java",20.1));
bookList.add(new Book(3,"计网",20.1));
return bookList;
}
//获取路径上的参数
@GetMapping(value = "/show/{id}")
@ResponseBody
public Book showBook(@PathVariable("id") int id){
Book book = new Book(1,"数据库",20.1);
System.out.println("get得到的id:"+id);
return book;
}
//获取json格式参数
@PostMapping("/updateBook")
@ResponseBody
public String updateBook(@RequestBody Book book){
System.out.println("updateBook:"+book.toString());
return "post";
}
@PutMapping("/addBook")
@ResponseBody
public String addBook(@RequestBody Book book){
System.out.println("addBook:" + book.toString());
return "put";
}
@DeleteMapping("/deleteBook")
@ResponseBody
public String delBook(int id){
System.out.println("delete得到的id:"+id);
return "delete";
}
}
3.2 REST风格
REST:即 Representational State Transfer。(资源)表现层状态转化。
是目前 最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便, 所以正得到越来越多网站的采用。
1、get 取,是查询数据,对应select操作 2、post 贴,常用于修改数据,对应update操作 3、put 放,常用于新增数据,对应insert操作 4、delete 删,是删除数据,对应delete操作
4. 域对象共享数据
1、ServletAPI
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
request.setAttribute("testScope", "hello,servletAPI");
return "success";
}
2、*ModelAndView
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
/**
* ModelAndView有Model和View的功能
* Model主要用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
ModelAndView mav = new ModelAndView();
//向请求域共享数据
mav.addObject("testScope", "hello,ModelAndView");
//设置视图,实现页面跳转
mav.setViewName("success");
return mav;
}
3、*Model
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testScope", "hello,Model");
return "success";
}
前端获取
<h2>获取Model的data:${requestScope.get("data")}</h2> 或者 <h2>获取Model的data:<%=request.getAttribute("data")%></%></h2>
示例
@Controller
public class DataTransController {
@RequestMapping("/books/show1")
public String testModel(Model model){
String data = "这是model方法";
model.addAttribute("data",data);
System.out.println("model1...");
return "page1";
}
@RequestMapping("/books/show2")
public String testModel2(Model model){
model.addAttribute("book",new Book(1,"python",11.1));
System.out.println("model2...");
return "page2";
}
@RequestMapping("/books/show3")
public ModelAndView testModelAndView(){
ModelAndView view = new ModelAndView();
view.addObject("data","这是modelAndView");
view.setViewName("page1");
System.out.println("modelAndView1...");
return view;
}
@RequestMapping("/books/show4")
public ModelAndView testModelAndView2(){
ModelAndView view = new ModelAndView();
view.addObject("book",new Book(2,"java",22.1));//数据绑定
view.setViewName("page2");//jsp名称
System.out.println("modelAndView2...");
return view;
}
}
4、map
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
map.put("testScope", "hello,Map");
return "success";
}
5、ModelMap
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testScope", "hello,ModelMap");
return "success";
}
6、Model、ModelMap、Map的关系
Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}
7、*向session域共享数据
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSessionScope", "hello,session");
return "success";
}
8、*向application域共享数据
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplicationScope", "hello,application");
return "success";
}
5. SSM整合
-
创建数据库
CREATE TABLE `book` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`price` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO `book`(`id`, `name`, `price`) VALUES (1, '假如给我三天光明', 89.20);
INSERT INTO `book`(`id`, `name`, `price`) VALUES (2, '杀死一只知更鸟', 78.30);
INSERT INTO `book`(`id`, `name`, `price`) VALUES (3, '茶花女', 89.40);
INSERT INTO `book`(`id`, `name`, `price`) VALUES (6, '白夜行', 100.00);
-
项目目录结构
(1)实体类pojo
注解开发 简化代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data //自动配置所有get\set\toString方法
@AllArgsConstructor //所有有参构造函数
@NoArgsConstructor //无参构造函数
public class Book {
private int id;
private String name;
private double price;
}
(2)Controller层
@Controller
public class BookController {
@Autowired
@Qualifier("BookServiceImpl")
private BookService bookService;
// 查询所有书籍
@RequestMapping("/allBook")
public String list(Model model) {
List<Book> books = bookService.queryAllBook();
model.addAttribute("bookList", books);
return "target"; //根据jsp页面名称返回
}
}
(3)service层
public interface BookService {
//增加一个Book
int addBook(Book book);
//根据id删除一个Book
int deleteBookById(int id);
//更新Book
int updateBook(Book book);
//根据id查询,返回一个Book
Book queryBookById(int id);
//查询全部Book,返回list集合
List<Book> queryAllBook();
//根据名字模糊查询
List<Book> searchBook(String name);
}
public class BookServiceImpl implements BookService {
//调用dao层的操作,设置一个set接口,方便Spring管理
private BookMapper bookMapper;
public void setBookMapper(BookMapper bookMapper) {
this.bookMapper = bookMapper;
}
public int addBook(Book book) {
return bookMapper.addBook(book);
}
public int deleteBookById(int id) {
return bookMapper.deleteBookById(id);
}
public int updateBook(Book book) {
return bookMapper.updateBook(book);
}
public Book queryBookById(int id) {
return bookMapper.queryBookById(id);
}
public List<Book> queryAllBook() {
return bookMapper.queryAllBook();
}
@Override
public List<Book> searchBook(String name) {
return bookMapper.queryBookByName(name);
}
}
(4)dao层
BookMapper.java
public interface BookMapper {
//增加一个Book
int addBook(Book book);
//根据id删除一个Book
int deleteBookById(int book_id);
//更新Book
int updateBook(Book book);
//根据id查询,返回一个Book
Book queryBookById(int book_id);
//查询全部Book,返回list集合
List<Book> queryAllBook();
//根据书名查询
List<Book> queryBookByName(String name);
}
BookMapper.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.ssm.dao.BookMapper">
<!--增加一个Book-->
<insert id="addBook" parameterType="Book">
insert into spring.book(id, name, price)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},#{price,jdbcType=DECIMAL})
</insert>
<!--根据id删除一个Book-->
<delete id="deleteBookById" parameterType="int">
delete from book
where id = #{id,jdbcType=INTEGER}
</delete>
<!--更新Book-->
<update id="updateBook" parameterType="Book">
update spring.book
set name = #{name},price = #{price}
where id = #{id}
</update>
<!--根据id查询,返回一个Book-->
<select id="queryBookById" resultType="Book">
select * from spring.book
where id = #{id}
</select>
<!--根据name查询,返回一个Book-->
<select id="queryBookByName" resultType="Book">
select * from spring.book
where name LIKE concat('%',#{name,jdbcType=VARCHAR},'%')
</select>
<!--查询全部Book-->
<select id="queryAllBook" resultType="Book">
SELECT * from spring.book
</select>
</mapper>
(5)整合配置文件
1、Spring整合MyBatis
jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
jdbc.username=root
jdbc.password=123456
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:jdbc.properties"/>
<!-- 2.数据库连接池 -->
<!--数据库连接池
dbcp 半自动化操作 不能自动连接
c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性 -->
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.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容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="com.ssm.dao"/>
</bean>
</beans>
注:
当我们在进行基于数据库的web程序开发时,我们可以先在主程序(如Servlet、Bean)中通过JDBC中的DriverManager建立数据库连接,然后将要对数据库进行操作的sql语句封装到Statement中,最后在返回结果集后断开数据库连接。以上是较为传统的开发模式,然而用这种模式开发会埋下严重的安全隐患:时间和内存资源消耗巨大,有内存泄漏的风险。
c3p0 是开源的JDBC连接池,c3p0连接池是在程序操作数据库之前预先根据配置文件创建一定数量的连接,当线程需要时直接取走,缩短了创建连接的时间,当使用完毕后,释放连接后放回连接池,以此类推,如果连接池中的连接使用完后,程序会根据配置文件配置的数据再次创建一批,使用完后放回连接池,并不是真正的关闭连接。(随取随用,用完放回)
mybatis-config.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>
<typeAliases>
<package name="com.ssm.pojo"/>
</typeAliases>
<mappers>
<mapper resource="com/ssm/dao/BookMapper.xml"/>
</mappers>
</configuration>
2、Spring整合service层
spring-service.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
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描service相关的bean -->
<context:component-scan base-package="com.ssm.service"/>
<!--BookServiceImpl注入到IOC容器中-->
<bean id="BookServiceImpl" class="com.ssm.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>
3、Springmvc层
-
web.xml
<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">
<welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list>
<!-- DispatcherServlet -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<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>
-
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">
<!-- <mvc:view-controller path="/hello" view-name="hello"></mvc:view-controller>-->
<!-- 配置SpringMVC -->
<!-- 1.开启SpringMVC注解驱动 -->
<mvc:annotation-driven />
<!-- 让Spring MVC不处理静态资源 .html .css .js .mp3-->
<!-- <mvc:default-servlet-handler />-->
<!-- 2.配置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>
<!-- 3.扫描web相关的bean -->
<context:component-scan base-package="com.ssm.controller" />
<!--
path:设置处理的请求地址
view-name:设置请求地址所对应的视图名称
-->
<!--过滤静态资源-->
<!-- <mvc:resources mapping="/jsp/**" location="WEB-INF/jsp/"/>-->
<!-- <mvc:resources mapping="/img/**" location="img/"/>-->
</beans>
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"
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>
(6)前端jsp
<%--
Created by IntelliJ IDEA.
User: LENOVO
Date: 2023/7/4
Time: 15:08
To change this template use File | Settings | File Templates.
--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table border="1" cellpadding="0" cellspacing="0" style="text-align: center;" id="dataTable">
<tr>
<th colspan="6">Book Info</th>
</tr>
<tr>
<th>id</th>
<th>书名</th>
<th>价格</th>
<th>操作1</th>
<th>操作2</th>
</tr>
<c:forEach var="book" items="${requestScope.get('bookList')}">
<tr>
<td>${book.getId()}</td>
<td>${book.getName()}</td>
<td>${book.getPrice()}</td>
<td><a href="/books/updateBook">修改</a></td>
<td><a href="/books/deleteBook/${book.getId()}">删除</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
效果
6. 常见错误
No dataSource: 没有整合applicationContext.xml
cannot resolve property bookmapper : BookServiceImpl没有BookMapper的set方法
bean 无法注入: 1.看web.xml中是否配置正确(注意classpath:文件命名是否一致。路径是否一致)
2.看applicationContext.xml中是否配置正确 (1)如果在applicationContext.xml中配置的bean,要检查<bean/ >的id是否和@autowired的一样, bean 的路径是否和service层一致 (2)如果使用了@service注解,要注意applicatinContext.xml中是否有扫描service的配置 <context:component-scan base-package=“service” /> base-package 就是service包的路径 没有这个的话无法获取service bean对象
3.是看自己使用@service是否起了另外的名字,如果没起的话就是一般默认将类名第一个开头的首字母小写,如果是两个或两个以上首字母开头的话bean默认为原类名,无论有没有起另外的名字,都检查一下是否有拼写错误这种低级问题
java.io.IOException: Could not find resource com/ssm/dao/BookMapper.xml: pom.xml文件中需要开启资源扫描路径
<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>
前端数据显示失败,需要引入常用的jstl标签库,prefix=“c”:为标签库起一个别名为c
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:forEach> 实现代码 </c:forEach>