SpringMVC ssm: MyBatis + Spring + SpringMVC ==MVC 三层架构==
MVC: 模型 (Dao, Service) 视图 (JSP) 控制器 (Servlet)
dao
service
servlet: 转发, 重定向
jsp / html
1、回顾 Servlet
导入所需依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <dependencies > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.16.RELEASE</version > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.2</version > </dependency > <dependency > <groupId > javax.servlet.</groupId > <artifactId > jstl</artifactId > <version > 1.2</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > servlet-api</artifactId > <version > 2.5</version > </dependency > </dependencies >
编写一个 Servlet 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class HelloServlet extends HttpServlet { @Override protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getParameter("method" ); if (method.equals("add" )) { req.getSession().setAttribute("msg" , "执行了 add 方法" );e } if (method.equals("delete" )) { req.getSession().setAttribute("msg" , "执行了 delete 方法" );e } req.getRequestDispatcher("/WEB-INF/jsp/test.jsp" ).forward(req, resp); } @Override protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); return ; } }
编写 Hello.jsp 在 WEB-INF 目录下新建一个 jsp 文件夹, 新建 test.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <%-- Created by IntelliJ IDEA. User: 雷神 Date: 2021 /9 /30 Time: 15 :39 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
在 web.xml 中注册 Servlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?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" > <servlet > <servlet-name > hello</servlet-name > <servlet-class > com.cu1.Servlet.HelloServlet</servlet-class > </servlet > <servlet-mapping > <servlet-name > hello</servlet-name > <url-pattern > /hello</url-pattern > </servlet-mapping > </web-app >
配置Tomcat 开启启动测试
MVC 框架要做哪些事情
将 url 映射到 java 类或 java 类方法
封装用户提交的数据
处理请求, 调用相关的业务处理 – 封装相应数据
将相应数据进行渲染 .jsp / html 等表示层数据
SpringMVC 特点:
轻量级
高效 基于请求相应的 MVC 框架‘
与 Spring 兼容性好, 无缝结合
约定优于配置
功能强大: RESful 数据验证, 格式化, 本地化, 主题等
简洁灵活
使用的人多
2、中心控制器 DispatcherServlet 最上层继承了 Servlet 所以其本质就是 Servlet
Spring 的 Web 框架围绕 DispatcherServlet 设计, DispatcherServlet 的作用是将请求分发到不同的处理器
从 Spring2.5 开始 使用 jAVA 5 或以上版本的用户可以采用基于注解的 controller
声明方式
SpringMVC 框架像许多其他 MVC 框架一样, 以请求为驱动, 围绕一个中心 Servlet 分派请求以及提供其他功能 DispatcherServlet 是一个实际的 Servlet (它继承自 HttpServlet 基类)
SpringMVC的原理如下图所示 :
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
3、Hello, SpringMVC
新建一个Moudle , springmvc-02-hello , 添加web的支持!
确定导入了SpringMVC 的依赖
配置web.xml, 注册DispatcherServlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?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" > <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-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
编写SpringMVC 的 配置文件! 名称: springmvc-servlet.xml : [servletname]-servlet.xml
说明,这里的名称要求是按照官方来的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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" > <bean class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean class ="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" id ="InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > <bean id ="/hello" class ="com.cu1.Controller.HelloController" /> </beans >
添加 处理映射器
1 <bean class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
添加 处理器适配器
1 <bean class ="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
添加 视图解析器
1 2 3 4 5 6 7 <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" id ="InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean >
编写要操作业务的Controller ,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.cu1.Controller;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.Controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class HelloController implements Controller { public ModelAndView handleRequest (HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mv = new ModelAndView(); mv.addObject("msg" ,"HelloSpringMVC!" ); mv.setViewName("hello" ); return mv; } }
将写好的 Controller
类交给SpringIOC容器,注册bean
1 <bean id ="/hello" class ="com.cu1.Controller.HelloController" />
写要跳转的jsp页面,显示ModelandView存放的数据,以及我们的正常页面;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <%-- Created by IntelliJ IDEA. User: 雷神 Date: 2021/10/5 Time: 21:08 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html > <head > <title > Title</title > </head > <body > ${msg} </body > </html >
配置Tomcat 启动测试
可能遇到的问题:访问出现404,排查步骤:
查看控制台输出,看一下是不是缺少了什么jar包。
如果jar包存在,显示无法输出,就在IDEA的项目发布中,添加lib依赖!
新建一个 lib 文件夹后点第一个 选中所有依赖后点击 Ok 即可
最后重启 Tomcat 即可
4、SpringMVC 执行原理
图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现
简要分析执行流程
DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
如上url拆分成三部分:
http://localhost:8080服务器域名
SpringMVC部署在服务器上的web站点
hello表示控制器
通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。
HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
Handler让具体的Controller执行。
Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
视图解析器将解析的逻辑视图名传给DispatcherServlet。
DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
最终视图呈现给用户。
5、SpringMVC 注解
编写 xml 文件
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?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" > <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-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
Springmvc-servlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd" > <context:component-scan base-package ="com.cu1.controller" /> <mvc:default-servlet-handler /> <mvc:annotation-driven /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" id ="internalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > </beans >
编写 controller 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Controller @RequestMapping("/h") public class HelloController { @RequestMapping("/hello") public String hello (Model model) { model.addAttribute("msg" , "Hello, SpringMVCAnnotation!" ); return "hello" ; } }
从注解名称上我们可以看到,@RequestMapping
注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
@RequestMapping 标识一个类:设置映射请求的请求路径的初始信息
@RequestMapping 标识一个方法:设置映射请求请求路径的具体信息
如果一个类上添加了 @RequestMapping
注解 那么就给这个类中所有的映射加上了一个初始 (父) 地址
流程:
首先通过 url 通过映射处理和查找控制器找到注解的相应映射的类中的方法
通过 HandlerAdapter
表示处理器适配器执行找到的方法
将返回值中的视图名传递给 HandlerAdapter
以及在类中封装的数据
显示视图
==说明==
若出现了 500
错误要将 pom.xml
以及 该项目的 JDK
版本降至 11
6、RestFul和控制器 控制器Controller
控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
控制器负责解析用户的请求并将其转换为一个模型。
在Spring MVC中一个控制器类可以包含多个方法
在Spring MVC中,对于Controller的配置方式有很多种
控制器 Controller
的使用方式有两种
在 3 中使用继承 Controller
并实现方法
使用 Controller
注解 (推荐该使用方式)
说明:
实现接口Controller定义控制器是较老的办法
缺点是:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦;
**使用注解 @Controller **
Controller
注解类型用于声明Spring类的实例是一个控制器(在讲IOC时还提到了另外3个注解);
Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。
多个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。
@RequestMapping 在 5 中进行了描述 此处略过
RestFul 风格 概念 Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。
测试代码 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Controller public class RestFulController { @GetMapping("/add/{a}/{b}") public String test (@PathVariable int a, @PathVariable int b, Model model) { int res = a + b; model.addAttribute("msg" , "add 结果为:" + res); return "add" ; } @PostMapping("/add/{a}/{b}") public String test1 (@PathVariable int a, @PathVariable int b, Model model) { int res = a + b; model.addAttribute("msg" , "add 结果1为:" + res + 5 ); System.out.printf("11111111111" ); return "add" ; } }
/{a}
表示取出 add
后参数将其赋值给变量 a
@PathVariable
注解为指定这个参数为接收前端传递的相对应的参数
若前端传递的为一个对象
1 2 3 4 5 6 7 8 9 @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private int age; }
这里使用 lombok
要注意使用版本不要过低 此处使用的为 1.18 版本
UserController:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Controller @RequestMapping("/user") public class UserController { @GetMapping("/t1") public String test1 (@RequestParam("username") String name, Model model) { System.out.println("接收到前端的参数为: " + name); model.addAttribute("msg" , name); return "add" ; } @GetMapping("/t2") public String test2 (User user) { System.out.println(user); return "add" ; } }
若是参数名与前端传递的参数不同, 需要 @RequestParam("username")
来指定接收参数的名字
要跳转的 jsp
页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <%-- Created by IntelliJ IDEA. User: 雷神 Date: 2021 /10 /7 Time: 15 :02 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="/SpringMVC_04/add/1/3" method="post" > <input type="submit" > </form> </body> </html>
注\: form 表单的路径应写完整 在提交时不会自动补全项目路径
思考:使用路径变量的好处?
使路径变得更加简洁;
获得参数更加方便,框架会自动进行类型转换。
通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如这里访问是的路径是/commit/1/a,则路径与方法不匹配,而不会是参数转换失败。
所有的地址栏请求默认都会是 HTTP GET 类型的。 方法级别的注解变体有如下几个:组合注解
1 2 3 4 5 @GetMapping @PostMapping @PutMapping @DeleteMapping @PatchMapping
关于 Model
Model 本质为一个接口, model
接收的为某一个实现类 此处大但猜测为 ModelMap
ModelMap
实现了除了 Model 必要的功能之外又扩展了更多的功能 但平时使用其实现的 Model
的接口已经够用了 Model
可以理解提供了更简易的功能
7、解决乱码 此处没啥好说的 直接使用 SpringMVC
提供的过滤器即可 配置在 web.xml
中
1 2 3 4 5 6 7 8 9 10 11 12 <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 >
更高级的自定义过滤器可以自行搜索
8、JSON 8.1、什么是JSON?
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。
采用完全独立于编程语言的文本格式 来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
在 JavaScript 语言中,一切都是对象。因此,任何JavaScript 支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。看看他的要求和语法格式:
对象表示为键值对,数据由逗号分隔
花括号保存对象
方括号保存数组
JSON 键值对 是用来保存 JavaScript 对象的一种方式,和 JavaScript 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值:
1 2 3 {"name" : "QinJiang" } {"age" : "3" } {"sex" : "男" }
JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
1 2 var obj = {a: 'Hello', b: 'World'}; var json = '{"a" : "Hello" , "b" : "World" }';
8.2、Jackson 的使用
Json
解决乱码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <mvc:annotation-driven > <mvc:message-converters > <bean class ="org.springframework.http.converter.StringHttpMessageConverter" > <constructor-arg value ="utf-8" > </constructor-arg > </bean > <bean class ="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" > <property name ="objectMapper" > <bean class ="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" > <property name ="failOnEmptyBeans" value ="false" > </property > </bean > </property > </bean > </mvc:message-converters > </mvc:annotation-driven >
导入 Jackson
的 jar
包
1 2 3 4 5 6 7 <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.11.2</version > </dependency >
编写 JsonUtils
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class JsonUtils { public static String getJson (Object object) { return getJson(object, "yyy-MM-dd HH:mm:ss" ); } public static String getJson (Object o, String dateFormat) { ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false ); SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); mapper.setDateFormat(sdf); String str = null ; try { str = mapper.writeValueAsString(o); } catch (JsonProcessingException e) { e.printStackTrace(); } return str; } }
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Controller public class UserController { @RequestMapping("/j1") @ResponseBody public String json1 () throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); User user = new User("Cu1" , 3 , "男" ); String str = mapper.writeValueAsString(user); return str; } @RequestMapping("/j2") @ResponseBody public String json2 () throws JsonProcessingException { ArrayList<User> userList = new ArrayList<>(); User user = new User("Cu1" , 3 , "男" ); User user1 = new User("Cu2" , 3 , "男" ); User user2 = new User("Cu3" , 3 , "男" ); userList.add(user); userList.add(user1); userList.add(user2); return JsonUtils.getJson(userList); } @RequestMapping("/j3") @ResponseBody public String json3 () throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); return JsonUtils.getJson(new Date(), "yyy-MM-dd HH:mm:ss" ); } }
关于 @RestController
和 ResponseBody
@ResponseBody
: 放在方法上, 返回值不会被视图解析器解析 而是直接将返回值传递给前端
@RestController
放在类上 即类中所有处理请求的方法返回值都不会被视图解析器解析 而是直接将返回值传递给前端
8.3、fastJson
导入 fastJson
的 jar
包
1 2 3 4 5 6 <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 1.2.78</version > </dependency >
fastJson
三个主要的类:
关于具体使用请参考 fastJson
9、整合 SSM 项目结构
9.1、整合 MyBatis
建立数据库 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 CREATE DATABASE `ssmbuild`;USE `ssmbuild`; DROP TABLE IF EXISTS `books`;CREATE TABLE `books` ( `bookID` INT (10 ) NOT NULL AUTO_INCREMENT COMMENT '书id' , `bookName` VARCHAR (100 ) NOT NULL COMMENT '书名' , `bookCounts` INT (11 ) NOT NULL COMMENT '数量' , `detail` VARCHAR (200 ) NOT NULL COMMENT '描述' , KEY `bookID` (`bookID`) ) ENGINE= INNODB DEFAULT CHARSET= utf8; INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES (1 ,'Java' ,1 ,'从入门到放弃' ), (2 ,'MySQL' ,10 ,'从删库到跑路' ), (3 ,'Linux' ,5 ,'从进门到进牢' );
将 MyBatis 与 Spring 整合
由于 MyBatis 与 Spring 整合后不需要再配置数据源 只需要设置别名日志 以及注册 Mapper 就可以了
mybatis-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings > <mappers > <mapper class ="com.cu1.dao.BookMapper" /> </mappers > </configuration >
Spring-dao.xml
==友情提示:== 千万不要使用 c3p0
数据源 不然你会怀疑人生 Spring
自带的数据源就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?xml version="1.0" encoding="UTF8"?> <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" > <context:property-placeholder location ="classpath:database.properties" /> <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.pwd}" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="sqlSessionFactoryBeanName" value ="sqlSessionFactory" /> <property name ="basePackage" value ="com.cu1.dao" /> </bean > </beans >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public interface BookMapper { int addBook (Books books) ; int deleteBookById (@Param("bookId") int id) ; int updateBook (Books books) ; Books queryBookById (@Param("bookId") int id) ; List<Books> queryAllBook () ; Books queryBookByName (String bookName) ; }
BookMapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.cu1.dao.BookMapper" > <insert id ="addBook" parameterType ="com.cu1.pojo.Books" > insert into ssmbuild.books (bookName, bookCounts, detail) values(#{bookName}, #{bookCounts}, #{detail}); </insert > <delete id ="deleteBookById" parameterType ="int" > delete from ssmbuild.books where bookID = #{bookId}; </delete > <update id ="updateBook" parameterType ="com.cu1.pojo.Books" > update ssmbuild.books set bookName = #{bookName}, bookCounts = #{bookCounts}, detail = #{detail} where bookID = #{bookID}; </update > <select id ="queryBookById" resultType ="com.cu1.pojo.Books" > select * from ssmbuild.books where bookID = #{bookId}; </select > <select id ="queryAllBook" resultType ="com.cu1.pojo.Books" > select * from ssmbuild.books; </select > <select id ="queryBookByName" resultType ="com.cu1.pojo.Books" > select * from ssmbuild.books where bookName = #{bookName}; </select > </mapper >
设计思想:
首先确定要实现的业务, 以接口的方式给出, 再使用 BookMapper.xml
绑定接口的 SQL
语句, 由于已经使用了包扫描机制 所以这里无需再写出接口的实现类 Spring
将以反射的机制来自动实现实现类
9.2、服务层的搭建 先以接口 BookService
的形式给出 Service
要实现的服务 然后使用 BookServiceImpl
继承 BookService
来实现所需要的服务 同时实现方法时直接调用 Dao
层相对应的服务实现方法即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface BookService { int addBook (Books books) ; int deleteBookById (int id) ; int updateBook (Books books) ; Books queryBooksById (int id) ; List<Books> queryAllBook () ; Books queryBookByName (String bookName) ; }
Service 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class BookServiceImpl implements BookService { private BookMapper bookMapper; public void setBookMapper (BookMapper bookMapper) { this .bookMapper = bookMapper; } @Override public int addBook (Books books) { return bookMapper.addBook(books); } @Override public int deleteBookById (int id) { return bookMapper.deleteBookById(id); } @Override public int updateBook (Books books) { return bookMapper.updateBook(books); } @Override public Books queryBooksById (int id) { return bookMapper.queryBookById(id); } @Override public List<Books> queryAllBook () { return bookMapper.queryAllBook(); } @Override public Books queryBookByName (String bookName) { return bookMapper.queryBookByName(bookName); } }
Spring-Service.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?xml version="1.0" encoding="UTF8"?> <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" > <context:component-scan base-package ="com.cu1.service" /> <bean id ="BookServiceImpl" class ="com.cu1.service.BookServiceImpl" > <property name ="bookMapper" ref ="bookMapper" /> </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > </beans >
9.3、整合 SpringMVC springmvc-servlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd" > <context:component-scan base-package ="com.cu1.controller" /> <mvc:default-servlet-handler /> <mvc:annotation-driven /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" id ="internalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > </beans >
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <?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" > <servlet > <servlet-name > DispatcherServlet</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:applicationContext.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > DispatcherServlet</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > <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-config > <session-timeout > 15</session-timeout > </session-config > <absolute-ordering /> </web-app >
==注意:==
1 2 3 <param-name > contextConfigLocation</param-name > <param-value > classpath:applicationContext.xml</param-value >
applicationContext.xml
是一个将上面的 Spring-dao.xml Spring-Service.xml springmvc-servlet.xml
汇总起来的总文件
applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 <?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 ="classpath:Spring-dao.xml" /> <import resource ="classpath:Spring-Service.xml" /> <import resource ="classpath:springmvc-servlet.xml" /> </beans >
Controller 层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 @Controller @RequestMapping("/book") public class BookController { @Autowired @Qualifier("BookServiceImpl") private BookService bookService; @RequestMapping("/allBook") public String list (Model model) { List<Books> books = bookService.queryAllBook(); model.addAttribute("list" , books); return "allBook" ; } @RequestMapping("/toAddBook") public String toAddPaper () { return "addBook" ; } @RequestMapping("/addBook") public String addBook (Books books) { bookService.addBook(books); return "redirect:/book/allBook" ; } @RequestMapping("/toUpdateBook/{bookId}") public String toUpdatePaper (@PathVariable("bookId") int id, Model model) { Books books = bookService.queryBooksById(id); model.addAttribute("books" , books); return "updateBook" ; } @RequestMapping("/updateBook") public String updateBooks (Books books) { bookService.updateBook(books); return "redirect:/book/allBook" ; } @RequestMapping("/deleteBook/{id}") public String deleteBook (@PathVariable("id") int id) { bookService.deleteBookById(id); return "redirect:/book/allBook" ; } @RequestMapping("/queryBook") public String queryBook (String queryBookName, Model model) { Books books = bookService.queryBookByName(queryBookName); List<Books> list = new ArrayList<Books>(); list.add(books); if (books == null ) { list = bookService.queryAllBook(); model.addAttribute("error" , "未查到" ); } model.addAttribute("list" , list); return "allBook" ; } }
到这里所有架构和配置文件已经完成,但是还没有导入 maven
依赖 如果按照视频上的版本或者不是比较新的版本
那么就会出现很多问题 排查起来太痛苦
这里强烈建议所需依赖全部导入最新版本!!!!
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 <?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 > <groupId > </groupId > <artifactId > </artifactId > <version > 1.0-SNAPSHOT</version > <properties > <maven.compiler.source > 11</maven.compiler.source > <maven.compiler.target > 11</maven.compiler.target > </properties > <dependencies > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.21</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > javax.servlet-api</artifactId > <version > 4.0.1</version > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.2</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > jstl</artifactId > <version > 1.2</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.7</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.6</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.5.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.3.9</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.12</version > </dependency > </dependencies > <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 > </project >
当你导入这些依赖之后 问题可能只解决了一部分 之前的问题被下面的错误取代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.IllegalArgumentException: More than one fragment with the name [spring_web] was found. This is not legal with relative ordering. See section 8.2.2 2c of the Servlet specification for details. Consider using absolute ordering. at org.apache.tomcat.util.descriptor.web.WebXml.orderWebFragments(WebXml.java:2200) at org.apache.tomcat.util.descriptor.web.WebXml.orderWebFragments(WebXml.java:2159) at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1124) at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:769) at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:299) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:94) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5176) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ... 10 more 21-Jan-2019 01:51:04.709 SEVERE [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Error deploying web application archive [C:\Users\dennismo\Dev\Projects\Production Prep\file-upload-module\webapps\file-upload-0.0.1-SNAPSHOT.war] java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/file-upload-0.0.1-SNAPSHOT]] at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:758) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:730) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:985) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1857) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
如果是使用了本文提供的 web.xml
应该就不会遇到这种报错 这一切都归功于 web.xml
中的 <absolute-ordering />
标签
9.4、前端的构建 上面都是处于服务端的实现 现在开始构建前端
addBook.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <%-- Created by IntelliJ IDEA. User: 雷神 Date: 2021 /10 /11 Time: 9 :55 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>增加</title> <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" > </head> <body> <div class ="container" > <div class ="row clearfix" > <div class ="col-md-12 column" > <div class ="page-header" > <h1> <small>新增书籍</small> </h1> </div> </div> </div> <<form action="${pageContext.request.contextPath}/book/addBook" method="post" > <div class ="form-group" > <label for ="bkname" >书籍名称</label> <input type=text name="bookName" class ="form-control" id="bkname" required> </div> <div class ="form-group" > <label for ="bknum" >书籍数量</label> <input type=text name="bookCounts" class ="form-control" id="bknum" required> </div> <div class ="form-group" > <label for ="bkdetail" >书籍描述</label> <input type=text name="detail" class ="form-control" id="bkdetail" required> </div> <div class ="form-group" > <input type="submit" class ="form-control" value="添加" > </div> </form> </div> </body> </html>
allBook.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- Created by IntelliJ IDEA. User: 雷神 Date: 2021 /10 /9 Time: 13 :29 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>书籍展示页面</title> <%--Bootstrap 美化界面--%> <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" > </head> <body> <div class ="container" > <div class ="row clearfix" > <div class ="col-md-12 column" > <div class ="page-header" > <h1> <small>书籍列表 -> 显示所有书籍</small> </h1> </div> </div> <div class ="row" > <div class ="color-md-4 column" > <%--toAddBook--%> <a class ="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook" >新增书籍</a> <a class ="btn btn-primary" href="${pageContext.request.contextPath}/book/allBook" >显示全部书籍</a> </div> <%--查询书籍--%> <div class ="color-md-4 column" > <form class ="form-inline" action="${pageContext.request.contextPath}/book/queryBook" method="post" style="float: right" > <span style="color: red; font-weight: bold" >${error}</span> <input type="text" name="queryBookName" class ="form-control" placeholder="请输入要查询的书籍名称" > <input type="submit" value="查询" class ="btn btn-primary" > </form> </div> </div> </div> <div class ="row clearfix" > <div class ="col-md-12 column" > <table class ="table table-hover table-striped" > <thead> <tr> <th>书籍编号</th> <th>书籍名称</th> <th>书籍数量</th> <th>书籍详情</th> <th>操作</th> </tr> </thead> <%-- 书籍从数据库中查询出来 从这个 list 中遍历出来--%> <tbody> <c:forEach var ="book" items="${list}" > <tr> <td>${book.bookID}</td> <td>${book.bookName}</td> <td>${book.bookCounts}</td> <td>${book.detail}</td> <td> <a href="${pageContext.request.contextPath}/book/toUpdateBook/${book.bookID}" >修改</a> | <a href="${pageContext.request.contextPath}/book/deleteBook/${book.bookID}" >删除</a> </td> </tr> </c:forEach> </tbody> </table> </div> </div> </div> </body> </html>
updateBook.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 <%-- Created by IntelliJ IDEA. User: 雷神 Date: 2021 /10 /11 Time: 10 :51 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>修改书籍</title> <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" > </head> <body> <div class ="container" > <div class ="row clearfix" > <div class ="col-md-12 column" > <div class ="page-header" > <h1> <small>修改书籍</small> </h1> </div> </div> </div> <<form action="${pageContext.request.contextPath}/book/updateBook" method="post" > <%--出现的问题 提交了修改 SQL 的请求 但是修改失败 初次考虑是事务出现问题 事务没有问题的情况下 查看 SQL 语句 看能否执行成功 此时前端要传递隐藏域 --%> <input type="hidden" name="bookID" value="${books.bookID}" > <div class ="form-group" > <label for ="bkname" >书籍名称</label> <input type=text name="bookName" class ="form-control" id="bkname" value="${books.bookName}" required> </div> <div class ="form-group" > <label for ="bknum" >书籍数量</label> <input type=text name="bookCounts" class ="form-control" id="bknum" value="${books.bookCounts}" required> </div> <div class ="form-group" > <label for ="bkdetail" >书籍描述</label> <input type=text name="detail" class ="form-control" id="bkdetail" value="${books.detail}" required> </div> <div class ="form-group" > <input type="submit" class ="form-control" value="修改" > </div> </form> </div> </body> </html>
index.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <%-- Created by IntelliJ IDEA. User: 雷神 Date: 2021 /10 /8 Time: 21 :31 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>书籍管理</title> <style> a{ text-decoration: none; color: black; font-size: 18px; } h3{ width: 180px; height: 38px ; margin: 100px auto; text-align: center; line-height: 38px; background: deepskyblue; border-radius: 5px; } </style> </head> <body> <h3> <a href="${pageContext.request.contextPath}/book/allBook" >进入书籍页面</a> </h3> </body> </html>