March 2, 2023

SpringMVC

Maven创建子项目卡住

这个问题是镜像没配置好的原因
image.png
参考JavaWeb的解决方法

MVC架构

什么是MVC架构?MVC是Model、View、Controller的缩写,他们三者的意思分别为:

所以顺序分别是View->Controller->Model,由外到里。在SpringMVC中这三者分别就对应Servlet,JSP,JavaBean

Servlet回顾

JavaWeb中我们学习了Servlet的使用,在这里就做一个页面跳转的小Demo来回顾复习一下,顺便学习一下EL和JSTL表达式

由一个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
package com.boogipop.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
if(method.equals("add")){
System.out.println("add");
req.getSession().setAttribute("msg","执行了add方法");
}
if(method.equals("delete")){
System.out.println("delete");
req.getSession().setAttribute("msg","执行了delete方法");
}
req.getRequestDispatcher("/jsp/test.jsp").forward(req,resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.boogipop.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>

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
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SpringMVC</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>springmvc-01</module>
<module>spring-02</module>
</modules>
<name>SpringMVC Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2 </version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
<!-- 指定java语言版本 -->
<build>
<finalName>SpringMVC</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

1
2
3
4
5
6
7
8
9
10
11
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>

源码如上已经给出,我们访问路由hello并且传参method会出现下面2种情况:
image.png
image.png
在这里首先利用到Servlet去对请求做处理和转发,然后在jsp中我们用el表达式获取了msg这个变量,在这里就先讲一下el表达式

EL表达式

EL 全名为Expression Language。EL主要作用:

使用EL的语法${....} EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、session、application四个域中查找相应的对象,找到则返回相应对象,找不到则返回”” (注意,不是null,而是空字符串)。
其中关于四个作用域的说法:

pageContext中最重要的方法:findAttribute方法,
使用pageContext.findAttribute方法能从
四个域(page, request, session, context)中寻找存储的数据,
查找的顺序也是从小到大(page—>request—>session—>context),
只要在某个域中能查到相对应的键值对,就返回,
如果四个域都没有则返回null。
这个方式对于EL表达式是最重要的,
例如JSP页面中有一个EL表达式: ${data}
最终在Servlet中就会被翻译成 pageContext.findAttribute(“data”)。

查找顺序是从小到大,在上述我们的Demo中,往session中设置了一个熟悉,然后通过el表达式取出来了,也可以使用如下方法获取各个域中的属性
image.png

例子就全部看博客吧

注意事项

EL表达式是JSP 2.0规范中的一门技术 。因此,若想正确解析EL表达式,需使用支持Servlet2.4/JSP2.0技术的WEB服务器。
注意:有些Tomcat服务器如不能使用EL表达式
(1)升级成tomcat6
(2)在JSP中加入<%@ page isELIgnored=”false” %>
image.png

JSTL表达式

跟着菜鸟教程看吧,看了一圈发现八九不离十

遇到的问题

首先就是EL表达式默认关闭这件事情,其次是Maven设置java语言版本好像有点他妈的bug
解决方法就是在pom中加入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    <properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!-- 下面的不要也可以好像 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>


第一个SpringMVC程序

这里我的环境是:tomcat10、jdk19
首先引入一下springmvc的依赖包:

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
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SpringMVC</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>springmvc-01</module>
<module>spring-02</module>
</modules>
<name>SpringMVC Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.4</version>
</dependency>
</dependencies>
<build>
<finalName>SpringMVC</finalName>
</build>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>

这里的spring-webmvc已经包含了spring里所有的内容,很方便,接下来就是创建我们的demo了:
首先需要配置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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 注册 dispatcher拦截servlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 关联一个springmvc的配置文件-->
<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>
<!-- / 匹配所有请求不包括jsp-->
<!-- /* 匹配所有请求包括jsp-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

然后需要配置springmvc配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- Handler-->
<bean id="/hello" class="com.boogipop.controller.TestController"/>
</beans>

其次准备一个Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.boogipop.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class TestController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 视图和模型
ModelAndView mv=new ModelAndView();
// 封装对象,放在modelview中
mv.addObject("msg","HelloSpringMVC");
// 封装要跳转的视图,放在modelview中
mv.setViewName("test"); //等同于/jsp/test.jsp 和spring的xml配置文件前后缀对应
return mv;
}
}

最后就是需要跳转的jsp页面

1
2
3
4
5
6
7
8
9
10
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>

最后当我们访问/hello路由的时候dispatcherservlet就会帮我们实现跳转,到达/jsp/test.jsp,但是url不会发生改变,这就和上面Servlet的例子一样
image.png
这就是一个简单的小案例

简单分析

在这/hello路由我们并没有在web.xml中设置,而是在spring的配置文件中注册了一个bean,当我们访问一个路由时,首先经过的就是dispatcherservlet,然后经过它转交到test.jsp,这一点对应spring配置文件中的:

1
2
3
4
5
6
7
8
9
10
11
	<!--        添加处理映射器-->
<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="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>

引入了处理映射器和处理适配器以及视图解析器,然后指定了前缀和后缀,这里指定的也就是view跳转的界面:
image.png
DispacherServlet就是在Web.xml中注册的唯一servlet,在SpringMVC中,任何路由都经过它的处理进行跳转,相当于一个中央控制器,我们跟进它的源码可以发现,它实际上就是HttpServlet的一个封装:
image.png

错误排查

https://www.cnblogs.com/wh521/p/16607474.html
https://www.cnblogs.com/ZhaiTangGuo/p/15987830.html
在这过程中也是遇到了很多狗血的错误,其中之一就是我们用的是SpringMVC6.0,因此jdk的版本和tomcat的版本也应该随之变化,在这里我们应该使用tomcat10,jdk也应该为高版本(1.8是不行的),假如tomcat低于10会web.xml会出现org.springframework.web.servlet.DispatcherServlet' is not assignable to 'javax.servlet.Servlet,jakarta.servlet.Servlet报错,这时候需要手动导入tomcat的依赖
除了这些以外在tomcat10中,pom依赖也随之改变了,主要体现在servlet和jsp上,tomcat10以下我们引入的是javax.servlet而在10我们引入jakarta.servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>

这里的tomcat10的依赖太他吗讲究了,老子都要哭了

SpringMVC原理分析

https://blog.csdn.net/yanweihpu/article/details/80366218
虽然这篇文章后半部分貌似有地方错了,但是前半部分还是没问题的

SpringMVC的执行流程如上:

  1. 客户端发送请求,到达DispacherServlet,解析请求对应的handler,在这里我们选择的映射器为BeanNameUrlHandlerMapping看名字就知道这是根据bean的id来设置对应的路由,比如我们第一个程序中的/hello
  2. 解析到对应的handler后,开始由HandlerAdapter适配器来处理
  3. HanlderAdapter会根据Handler来处理对应的请求,并处理相关业务逻辑
  4. 处理器处理完业务后,返回一个ModelAndView对象,Model是返回的数据对象,View是视图
  5. ViewResolver会根据逻辑View查找实际的View(jsp/test.jsp)
  6. DispacherServlet把返回的Model传给View
  7. 通过View返回请求者

使用注解开发SpringMVC

使用注解进行开发就有点像Flask和SpringBoot了,很方便,实在是方便,在这之前又发现了一个问题:
https://blog.csdn.net/zhangphil/article/details/127134127
image.png
解决方法如上,有效,诶妈的,框架这些弯钩东西bug怎么这么多,草拟吗的
我们先新建一个子Maven项目:

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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 注册 dispatcher拦截servlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 关联一个springmvc的配置文件-->
<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>
<!-- / 匹配所有请求不包括jsp-->
<!-- /* 匹配所有请求包括jsp-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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">
<context:component-scan base-package="com.boogipop.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>

在这里我们的Springmvc配置文件只开启了一个包扫描conponent-scan功能,为什么没加上之前的几个适配器和映射器呢?
image.png
我们之前加这些其实是为了解释原理,在Spring中会自动为我们装配好的,这是默认装配的东西,因此可以去掉,接下来我们用注解写一个Controllor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.boogipop.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ControllerTest {
@RequestMapping("/hello")
public String redirect(Model model, HttpServletRequest req, HttpServletResponse resp){
model.addAttribute("msg","Hello AnnotationSpringMVC!");
return "hello";
}
}

由于配置了扫描包,因此Spring会识别注解,这里@Controller就是之前说的@Component注解,只是在不同的层称呼不同

同样很好理解,@RequestMapping注解就是用来设置路由的,然后这我们就没有继承Controllor接口了,这里直接传入一个Model对象,这个model就和之前的ModelandView对象一样,效果是相同的
最后还有一点,requestmapping下函数返回值为String时,会进行页面跳转,比如这里就会跳转到/jsp/hello.jsp,和之前说的也是一样的
image.png

Controller配置总结

到这里我们一共学了两套方法去配置Controller,第一种就是按照原理去配置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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 注册 dispatcher拦截servlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 关联一个springmvc的配置文件-->
<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>
<!-- / 匹配所有请求不包括jsp-->
<!-- /* 匹配所有请求包括jsp-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- Handler-->
<bean id="/hello" class="com.boogipop.controller.TestController"/>
</beans>

第二种

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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 注册 dispatcher拦截servlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 关联一个springmvc的配置文件-->
<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>
<!-- / 匹配所有请求不包括jsp-->
<!-- /* 匹配所有请求包括jsp-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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">
<context:component-scan base-package="com.boogipop.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>

RequestMapping

在上面也说了,@RequestMapping注解可以用来设置路由,这个注解是放在方法上面的,但同时也可以放在一个类上:
image.png
这时加入我们还想访问到hello.jsp,那我们的路由就得是/test/hello,这种设置方法我个人觉得很鸡肋没啥用,就是加一个路由前缀罢了

RestFul风格讲解

RestFul是一种开发的风格,一种规范,而不是什么配置,基于这个风格可以使开发更简洁,更有层次,更易于实现缓存机制
传统请求方式:

传统请求方式是根据传参和对应的控制器来实现增删改查,而在RestFul风格中,会变为:
GET :/users # 查询用户信息列表
GET :/users/1001 # 查看某个用户信息
POST :/users # 新建用户信息
PUT :/users/1001 # 更新用户信息(全部字段)
PATCH :/users/1001 # 更新用户信息(部分字段)
DELETE :/users/1001 # 删除用户信息
RestFul风格根据请求方式和对应的路由来判断,这样需要的Controllor就会大大减少
配置文件不改名,我们就换一个Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.boogipop.controller;

import com.oracle.wls.shaded.org.apache.xpath.operations.Mod;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;

@Controller
public class RestFulController {
@RequestMapping("/add/{a}/{b}")//这里用双引号,又忘了
public void control(@PathVariable int a,@PathVariable int b,Model model, HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getWriter().println("pathvar:"+a+b);
}
}

我们用到了一个新注解@PathVariable,这个东西和我们再django学的很相似
image.png
这样我们就可以简单的体验一下RestFul风格,然后这里再讲一下如何设置我们的请求方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.boogipop.controller;

import com.oracle.wls.shaded.org.apache.xpath.operations.Mod;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.IOException;

@Controller
public class RestFulController {
@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.POST)//这里用双引号,又忘了
public void control(@PathVariable int a,@PathVariable String b,Model model, HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getWriter().println("pathvar:"+a+b);
}
}

这里我修改了一下a,b的类型注意一下,b改为了String,测试一下能否转换类型,并且指定POST请求访问:
image.png
用GET访问已经不行了,我们换成POST:
image.png
完美解决问题,这里通过method = RequestMethod.POST来指定路由的请求类型
还有一个需要注意点就是这里既然指定了method,那么前面路由也必须加一个value=(name=是不可以的,测试过了,会报错)
image.png
这里也要指定路由的名字value或者是path

请求方式Mapping

我们前面通过RequestMethod.POST来指定请求类型,这样未免太复杂了,其实spring给我们准备好了对应的路由,比如POST方式的叫做@PostMapping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.boogipop.controller;

import com.oracle.wls.shaded.org.apache.xpath.operations.Mod;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

@Controller
public class RestFulController {
@PostMapping( "/add/{a}/{b}")//这里用双引号,又忘了
public void control1(@PathVariable int a,@PathVariable String b,Model model, HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getWriter().println("POST pathvar:"+a+b);
}
@GetMapping( "/add/{a}/{b}")//这里用双引号,又忘了
public void control2(@PathVariable int a,@PathVariable String b,Model model, HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getWriter().println("Get pathvar:"+a+b);
}
}

这里只需要用对应的请求方式加一个Mapping即可:
image.png
经过测试成功:
image.png
image.png

这里就是对RestFul风格的一些简短介绍

重定向和转发

在JavaWeb中我们学习了两种重定向的方法,一种是转发,用的是request.getRequestDispatcher().另一种是重定向,用的是response.sendRedirect();
二者区别主要体现在URL是否改变,转发是将请求转发到目标界面,把目标界面的回显在当前页面显示,而重定向则是多一次请求,直接跳转到目标界面,前者URL不改变,后者URL改变
在SpringMVC中同样也存在着重定向和转发,他们的关键词分别是redirect:forward:,我们首先把视图解析器注释掉:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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">
<context:component-scan base-package="com.boogipop.controller"/>
<!-- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> -->
<!-- 前缀-->
<!-- <property name="prefix" value="/jsp/"/> -->
<!-- 后缀-->
<!-- <property name="suffix" value=".jsp"/> -->
</bean>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.boogipop.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RedirectController {
@RequestMapping("/redirect")
public String redirect(Model model, HttpServletRequest request, HttpServletResponse response){
return "/jsp/redirect.jsp";
}
}

这种情况下,我们的请求不会经过视图解析器,因此需要手动添加前缀和后缀:
image.png
可以看到成功跳转,接着我们把视图解析器取消注释,然后修改Controller为如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.boogipop.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RedirectController {
@RequestMapping("/redirect")
public String redirect(Model model, HttpServletRequest request, HttpServletResponse response){
return "forward:/jsp/redirect.jsp";
}
}

forward关键字是转发的意思,加了forward关键词后会无视视图解析器,直接转发:
image.png
我们再次修改关键词为redirect:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.boogipop.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RedirectController {
@RequestMapping("/redirect")
public String redirect(Model model, HttpServletRequest request, HttpServletResponse response){
return "redirect:/jsp/redirect.jsp";
}
}

这种情况就是重定向了,URL会变化:
image.png
很简单的重定向和转发案例,理解起来轻松~

接收请求和数据回显

接收数据

在JavaWeb中我们是依靠request.getParameter()去获取前台传入的数据,而在SpringMVC中有两种方式,注解和直接获取,我们可以做一个小案例来解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.boogipop.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RedirectController {
@RequestMapping("/redirect")
public String redirect(Model model,String name,int age){
System.out.println(name);
System.out.println(age);
return "redirect";

}
}

我们传参:[http://localhost:8080/redirect?name=kino&age=15](http://localhost:8080/redirect?name=kino&age=15)
image.png
在后台即可获取对应的数据,SpringMVC会帮我们识别参数

另外假如我们URL中传入的参数名称和方法中的形参名称不相同,我们可以通过注解的方法去让他识别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.boogipop.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class RedirectController {
@RequestMapping("/redirect")
public String redirect(Model model, @RequestParam("username") String name){
System.out.println(name);
return "redirect";

}
}

这时候我们需要传入一个username后台才能获取参数的值:
[http://localhost:8080/redirect?username=testuser](http://localhost:8080/redirect?username=testuser)
image.png

那我们可不可以接受一个对象呢?答案是可以的,我们先定义一个pojo类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.boogipop.pojo;

public class User {
private String name;

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", score=" + score +
", age=" + age +
'}';
}

private int score;
private int age;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.boogipop.controller;

import com.boogipop.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class RedirectController {
@RequestMapping("/redirect")
public String redirect(Model model, User user){
System.out.println(user);
return "redirect";

}
}

这个时候我们传参[http://localhost:8080/redirect?name=Boogipop&score=100&age=18](http://localhost:8080/redirect?name=Boogipop&score=100&age=18)会发现:
image.png
值完全都没注入进去,这其实和Spring的Bean装配是一个道理,因此我们需要给它加上set和get方法:
image.png
加上之后就正常了

数据回显到前端

在Javaweb我们用的是resp.getWriter().Println()去进行回显的,在SpringMVC中有三种,分别是ModelandVIew Model ModelMap
其中ModelandView在一开始我们就知道了其用法:

1
2
3
4
5
6
7
8
9
10
11
12
public class TestController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 视图和模型
ModelAndView mv=new ModelAndView();
// 封装对象,放在modelview中
mv.addObject("msg","HelloSpringMVC");
// 封装要跳转的视图,放在modelview中
mv.setViewName("test"); //等同于/jsp/test.jsp 和spring的xml配置文件前后缀对应
return mv;
}
}

而Model的用法我们在上面也用到了,ModelMap和Model的用法师一样的,只不过是继承关系,继承关系为Model->ModelMap->LinkHashMap,Model继承了ModelMap继承了LinkHashMap,用法就不多赘述,和上面一模一样

乱码问题解决

response.getWriter()造成的乱码

在SpringMVC架构中,假如往页面回显中文的时候,可能就会出现乱码的问题,这时候就需要解决乱码问题,可能有的人一开始会认为用requset去设置servlet请求和回显的编码就行,实际上是行不通的,这是因为中央控制器DispacherServlet是SpringMVC设置的,不是一般的servlet,因此我们需要更早拦截,也就是自定义filter

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
package com.boogipop.controller;

import com.boogipop.pojo.User;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;

@Controller
public class RedirectController {
@RequestMapping("/redirect")
public String redirect(Model model, User user){
System.out.println(user);
return "redirect";

}
@RequestMapping("/chinese")
public void encode(String name, HttpServletRequest request , HttpServletResponse response) throws IOException {
System.out.println(name);
response.getWriter().println(name);
}
}

Controller基本配置如下,我们正常传入一个中文,结果如下:
image.pngimage.png
会出现乱码的问题,解决这个乱码的问题很简单,我们多加入一段代码:

1
2
3
4
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println(name);

这样即可解决
image.png
但是接受控制台参数就是会乱码,这个改不了啊啊啊啊,等以后看看能不能解决吧呜呜呜

Jsp跳转界面的乱码

我们测试的代码如下:

1
2
3
4
5
@RequestMapping("/chinese2")
public String coding(Model model,String name){
model.addAttribute("msg",name);
return "redirect";
}
1
2
3
4
5
6
7
8
9
10
11
12
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>

<html>
<head>
<title>Title</title>
</head>
<body>
<h1>REDIRECT PAGE</h1>
${msg}
</body>
</html>

有三种配置

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
package com.boogipop.filters;

import jakarta.servlet.*;

import java.io.IOException;

public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}

@Override
public void destroy() {
Filter.super.destroy();
}
}

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
100
101
102
103
104
105
106
107
package com.boogipop.filters;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

public class SpecialFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
filterChain.doFilter(myrequest, response);
}

@Override
public void destroy() {
Filter.super.destroy();
}

//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;

//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}

// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}

//取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}

//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
<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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>

@ResponseBody和return造成的乱码

1
2
3
4
5
@RequestMapping("/chinese3")
@ResponseBody
public String coding2(Model model,String name) throws UnsupportedEncodingException {
return "我是好人";
}

image.png
我们只需要加上produces = "text/html;charset=UTF-8"
image.png

JackJson、FastJson2(推荐FastJson2)

由于他妈的上面的乱码实在是给我带来了许多震撼,真的
首先JSON我反正是已经很熟悉了,我就不介绍了,我脑里还游荡者上一波的中文乱码问题,我草,真的纯畜
先讲一下JackJson吧,首先是依赖包

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>

其次之前我们提到过了加上@ResponseBody注解之后,return单纯就是返回一个字符串而已,然后JSON中也同样会出现JSON乱码的问题,有2种解决方法,第一种是在RequestMapping处加东西:@RequestMapping(value = "/json2",produces = "text/html;charset=UTF-8")
第二种则是修改springMvc的配置文件,一劳永逸:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
<value>text/plain;charset=UTF-8</value>
<value>application/xml;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

这两种都可以解决问题,这里我就选择后者了

RestController

一个小tips,这个注解放在类上就相当于给每个方法都加了Responsebody注解

JackJson用法

用法很简单:

1
2
3
4
5
6
7
8
@ResponseBody
@RequestMapping("/json1")
public String json1(Model model,String name) throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
User user=new User("高贝克",100,18);
String s = mapper.writeValueAsString(user);
return s;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@ResponseBody
@RequestMapping(value = "/json2")
public String json2(Model model,String name) throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
User user1=new User("高贝克",100,18);
User user2=new User("高贝克1",100,18);
User user3=new User("高贝克3",100,18);
User user4=new User("高贝克4",100,18);
List<User> list=new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
String s = mapper.writeValueAsString(list);
return s;
}

以上两种方法对应的输出结果为:
image.pngimage.png
符合JSON的格式规范,除此之外它还能用来对日期做转换:

1
2
3
4
5
6
@RequestMapping("/json3")
@ResponseBody
public String data() throws JsonProcessingException {
Date date=new Date();
return new ObjectMapper().writeValueAsString(date);
}

正常来说返回值应该是一个时间戳:
image.png这里假如我们想要将其转换为标准格式该怎么做呢,传统做法是用new SimpleDateFormat().format(new Date())来实现的,但是JackJson给了一种方法:

1
2
3
4
5
6
@RequestMapping("/json3")
public String data() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
return mapper.writeValueAsString(new Date());
}

image.png
其实我觉得都差不多,根据这个东西我们可以写一个工具类来帮我做转换,如果是普通对象那就直接JSON格式输出,是日期就转换格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.boogipop.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.text.SimpleDateFormat;

public class JsonUtil {
public static String gerjson(Object o) throws JsonProcessingException {
return gerjson(o,"yy-MM-dd HH:mm:ss");
}
public static String gerjson(Object o,String format) throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat(format));
return mapper.writeValueAsString(o);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RequestMapping("/json3")
public String data() throws JsonProcessingException {
return JsonUtil.gerjson(new Date());
}
@RequestMapping("/json4")
public String json4() throws JsonProcessingException {
User user1=new User("高贝克",100,18);
User user2=new User("高贝克1",100,18);
User user3=new User("高贝克3",100,18);
User user4=new User("高贝克4",100,18);
List<User> list=new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
return JsonUtil.gerjson(list);
}

image.png
image.png
输出结果与之对应,工具里面把getjson方法利用达到了最大

FastJson使用(控制台乱码破案)

首先到这里破案了,是Jdk的版本太高,之前用的是19,换成17的之后立马没问题了呜呜呜呜
image.png
FastJson使用也很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RequestMapping("/json5")
public void fastjson(){
User user1=new User("高贝克",100,18);
User user2=new User("高贝克1",100,18);
User user3=new User("高贝克3",100,18);
User user4=new User("高贝克4",100,18);
List<User> list=new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
System.out.println("Java对象转JSON字符串");
String str1= JSON.toJSONString(list);
String str2=JSON.toJSONString(user1);
System.out.println(str1);
System.out.println("JSON字符串转Java对象");
User user = JSON.parseObject(str2, User.class);
System.out.println(user);
System.out.println("java对象转json对象");
Object o = JSON.toJSON(user);
System.out.println(o);
}

image.png其实我感觉FastJson更好用,真的,我以后就用FastJson了

SSM整合:环境搭建

依赖包:

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
  <dependencies>
<!-- 注解库 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependency>
<!-- servlet、jsp、JSTL -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- springmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.4</version>
</dependency>
<!-- jackjson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<!-- fastson -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.23</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.0.4</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.1</version>
</dependency>
<!-- aop织入包 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<!-- c3p0连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
</dependencies>

初始化数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE DATABASE ssmbuild;
USE ssmbuild;
CREATE TABLE `books`(
`bookID` INT NOT NULL AUTO_INCREMENT COMMENT '书id',
`bookName` VARCHAR(100) NOT NULL COMMENT '书名',
`bookCounts` INT 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层

mybatis层就是pojo类和mapper以及service:

1
2
3
4
5
6
7
8
9
10
11
12
<?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>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.boogipop.pojo"/>
</typeAliases>
</configuration>
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
package com.boogipop.pojo;

import org.apache.ibatis.type.Alias;

@Alias("Books")
public class Books {
private int bookID;
private String bookName;
private int bookCounts;
private String detail;

@Override
public String toString() {
return "Books{" +
"bookID=" + bookID +
", bookName='" + bookName + '\'' +
", bookCounts=" + bookCounts +
", detail='" + detail + '\'' +
'}';
}

public int getBookID() {
return bookID;
}

public void setBookID(int bookID) {
this.bookID = bookID;
}

public String getBookName() {
return bookName;
}

public void setBookName(String bookName) {
this.bookName = bookName;
}

public int getBookCounts() {
return bookCounts;
}

public void setBookCounts(int bookCounts) {
this.bookCounts = bookCounts;
}

public String getDetail() {
return detail;
}

public void setDetail(String detail) {
this.detail = detail;
}

public Books(int bookID, String bookName, int bookCounts, String detail) {
this.bookID = bookID;
this.bookName = bookName;
this.bookCounts = bookCounts;
this.detail = detail;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.boogipop.mapper;

import com.boogipop.pojo.Books;

import java.util.List;
import java.util.Map;

public interface BooksMapper {
//增加
Boolean AddBook(Books book);
//删除
Boolean DelBook(int id);
//修改
Boolean UpdateBook(Map<Object,Object> map);
//查询所有
List<Books> SelectAllBooks();
//查询某一本书
Books SelectBookById(int id);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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.boogipop.mapper.BooksMapper">
<select id="SelectAllBooks" resultType="Books">
select * from books
</select>
<select id="SelectBookById" resultType="Books" parameterType="int">
select * from books where id=#{id}
</select>
<insert id="AddBook" parameterType="Books">
insert into books(bookName,bookCounts,detail) values (#{bookName},#{bookCounts},#{detail})
</insert>
<update id="UpdateBook" parameterType="map">
update books set bookName=#{bookname},bookCounts=#{bookcounts},detail=#{detail} where bookID=#{id}
</update>
<delete id="DelBook" parameterType="int">
delete from books where bookID=#{id}
</delete>
</mapper>

Spring层

Spring需要做的就是整合mybatis,以及注册bean

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
<?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">
<context:property-placeholder location="db.properties"/>

<context:component-scan base-package="com.boogipop.mapper"/>
<context:component-scan base-package="com.boogipop.service"/>

<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"/>
<!-- 关闭连接池后不自动提交-->
<property name="autoCommitOnClose" value="false"/>
<!-- 响应超时时长-->
<property name="checkoutTimeout" value="10000"/>
<!-- 失败重连次数-->
<property name="acquireRetryAttempts" value="2"/>
</bean>

<!-- 获取sqlsessionfactory-->
<bean id="sqlsessionfactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--绑定mybatis配置文件-->
<property name="dataSource" ref="datasource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/boogipop/mapper/*Mapper.xml"/>
</bean>

<!--加载mapper包中的所有接口,通过sqlSessionFactory获取sqlSession对象,然后创建所有的dao接口并存储在Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 这里的value和上面sqlsessionfactory的id对应 -->
<property name="sqlSessionFactoryBeanName" value="sqlsessionfactory"/>
<property name="basePackage" value="com.boogipop.mapper"/>
</bean>

<!--声明式事务配置-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<!--注入数据源-->
<property name="dataSource" ref="datasource"/>
</bean>

</beans>
1
2
3
4
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&seUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=jiayou357753

现在可以写个测试类试一下SQL执行是否正常:

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
import com.boogipop.mapper.BooksMapper;
import com.boogipop.pojo.Books;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestSql {
@Test
public void selectall(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
BooksMapper bookMapper = context.getBean("booksMapper", BooksMapper.class);
List<Books> books = bookMapper.SelectAllBooks();
for (Books book : books) {
System.out.println(book);
}
}
@Test
public void add(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
BooksMapper bookMapper = context.getBean("booksMapper", BooksMapper.class);
Books book=new Books(7,"HackerBook",100,"黑客从0到1");
if (bookMapper.AddBook(book)) {
System.out.println("add successfully");
}
}
@Test
public void del(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
BooksMapper bookMapper = context.getBean("booksMapper", BooksMapper.class);
if (bookMapper.DelBook(4)) {
System.out.println("del successfully");
}
}
@Test
public void update(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
BooksMapper bookMapper = context.getBean("booksMapper", BooksMapper.class);
Map<Object,Object> map=new HashMap<>();
map.put("bookname","Web");
map.put("bookcounts","8");
map.put("detail","web from boogipop");
map.put("id",5);
if (bookMapper.UpdateBook(map)) {
System.out.println("update successfully");
}
}
}

image.png

SpringMVC层

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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 乱码-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<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>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--session十五分钟-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>

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
<?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">
<context:property-placeholder location="db.properties"/>

<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"/>
<!-- 关闭连接池后不自动提交-->
<property name="autoCommitOnClose" value="false"/>
<!-- 响应超时时长-->
<property name="checkoutTimeout" value="10000"/>
<!-- 失败重连次数-->
<property name="acquireRetryAttempts" value="2"/>
</bean>

<!-- 获取sqlsessionfactory-->
<bean id="sqlsessionfactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--绑定mybatis配置文件-->
<property name="dataSource" ref="datasource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/boogipop/mapper/*Mapper.xml"/>
</bean>

<!--加载mapper包中的所有接口,通过sqlSessionFactory获取sqlSession对象,然后创建所有的dao接口并存储在Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 这里的value和上面sqlsessionfactory的id对应 -->
<property name="sqlSessionFactoryBeanName" value="sqlsessionfactory"/>
<property name="basePackage" value="com.boogipop.mapper"/>
</bean>

<!--声明式事务配置-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<!--注入数据源-->
<property name="dataSource" ref="datasource"/>
</bean>

</beans>
1
2
3
4
5
6
7
<?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">
<context:component-scan base-package="com.boogipop.mapper"/>
</beans>
1
2
3
4
5
6
7
<?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">
<context:component-scan base-package="com.boogipop.service"/>
</beans>

将之后我们需要注入的实现类impl注册,并且整合进springmvc-servlet文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.boogipop.service;

import com.boogipop.pojo.Books;

import java.util.List;
import java.util.Map;

public interface BookService {
//增加
Boolean AddBook(Books book);
//删除
Boolean DelBook(int id);
//修改
Boolean UpdateBook(Map<Object,Object> map);
//查询所有
List<Books> SelectAllBooks();
//查询某一本书
Books SelectBookById(int id);

}

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
package com.boogipop.service;

import com.boogipop.mapper.BooksMapper;
import com.boogipop.pojo.Books;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
@Component
public class BookServiceImpl implements BookService{
@Autowired
private BooksMapper booksMapper;
@Override
public Boolean AddBook(Books book) {
return booksMapper.AddBook(book);
}

@Override
public Boolean DelBook(int id) {
return booksMapper.DelBook(id);
}

@Override
public Boolean UpdateBook(Map<Object, Object> map) {
return booksMapper.UpdateBook(map);
}

@Override
public List<Books> SelectAllBooks() {
return booksMapper.SelectAllBooks();
}

@Override
public Books SelectBookById(int id) {
return booksMapper.SelectBookById(id);
}
}

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
<?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:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--将mapper整合进来-->
<import resource="ApplicationContext.xml"/>
<import resource="mapperbean.xml"/>
<import resource="servicebean.xml"/>
<!--包扫描-->
<context:component-scan base-package="com.boogipop.controller"/>
<!-- 静态资源过滤-->
<mvc:default-servlet-handler/>
<!-- 注解驱动,静态资源过滤会导致注解驱动失效,因此必须补上-->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>

到此树状图为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SSM
├─src
└─main
├─java
│ └─com
│ └─boogipop
│ ├─controller
│ ├─mapper
│ ├─pojo
│ ├─service
│ └─utils
├─resources
├─test
└─webapp
├─jsp
└─WEB-INF

SSM整合:查询书籍功能

坑点注意

首先是开启了静态资源过滤时,回导致默认的注解驱动失效,导致无法扫描到controller造成404,因此正确的配置应该改为:

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
<?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:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--将mapper整合进来-->
<import resource="ApplicationContext.xml"/>
<import resource="mapperbean.xml"/>
<import resource="servicebean.xml"/>
<!--包扫描-->
<context:component-scan base-package="com.boogipop.controller"/>
<!-- 静态资源过滤-->
<mvc:default-servlet-handler/>
<!-- 注解驱动,静态资源过滤会导致注解驱动失效,因此必须补上-->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>

然后还有一个坑点就是假如爆了500,Unsatisfiled错误,那就是说明我们的bean文件没有关联到一起,我们首先自定义了一个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
package com.boogipop.controller;

import com.boogipop.pojo.Books;
import com.boogipop.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
@Qualifier("bookServiceImpl")
private BookService bookService;
@RequestMapping("/allbooks")
public String booklist(Model model){
System.out.println(bookService);
List<Books> books = bookService.SelectAllBooks();
for (Books book : books) {
System.out.println(book);
}
model.addAttribute("msg","test");
return "allbooks";

}
}

在这里设置了私有属性bookservice,因此我们要将servicebean.xml和ApplicationContext.xml以及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
package com.boogipop.controller;

import com.boogipop.pojo.Books;
import com.boogipop.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
@Qualifier("bookServiceImpl")
private BookService bookService;
@RequestMapping("/allbooks")
public String booklist(Model model){
System.out.println(bookService);
List<Books> books = bookService.SelectAllBooks();
model.addAttribute("books",books);
return "allbooks";

}
}
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
<html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<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/allbooks">进入书籍界面</a>
</h3>
</body>
</html>
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
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 22927
Date: 2023/2/2
Time: 22:19
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<title>书籍展示</title>
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>书籍列表 ———— 显示所有数据</small>
</h1>
</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>
</tr>
</thead>
<tbody>
<c:forEach var="book" items="${books}">
<tr>
<td>${book.bookID}</td>
<td>${book.bookName}</td>
<td>${book.bookCounts}</td>
<td>${book.detail}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

最后页面的效果如下!
image.png
还是比较好看的QWQ

SSM整合: 增加书籍功能

增加书籍功能和实现查询功能是一样的,大致就分为controller创建,JSP编写,返回视图:
Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RequestMapping("/toaddbook")
public String toaddbook(Model model){
return "addbook";
}
@PostMapping("/addbook")
public String addbook(Model model,Books books) throws Exception {
Boolean add = bookService.AddBook(books);
if(add){
System.out.println("add successfully");
}
else{
throw new Exception("添加错误");
}
return "redirect:/book/allbooks";
}

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

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<title>添加书籍</title>
</head>
<body>
<div>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">新建部门</h3>
</div>
<div class="panel-body">
<form action="${pageContext.request.contextPath}/book/addbook" method="post">
<div class="form-group">
<label >书籍名称</label>
<input type="text" class="form-control" placeholder="书籍名称" name="bookName" required="required">
</div>
<div class="form-group">
<label >书籍数量</label>
<input type="text" class="form-control" placeholder="书籍数量" name="bookCounts" required="required">
</div>
<div class="form-group">
<label >书籍详情</label>
<input type="text" class="form-control" placeholder="书籍详情" name="detail" required="required">
</div>
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
</div>
</div>
</body>
</html>

然后在allbooks界面添加一下进入添加界面的入口:

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
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 22927
Date: 2023/2/2
Time: 22:19
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<title>书籍展示</title>
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>书籍列表 ———— 显示所有数据</small>
</h1>
</div>
</div>
</div>
<%--添加书籍界面--%>
<div class="row">
<div class="col-md-4 column">
<a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toaddbook">新增书籍</a>
</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>
</tr>
</thead>
<tbody>
<c:forEach var="book" items="${books}">
<tr>
<td>${book.bookID}</td>
<td>${book.bookName}</td>
<td>${book.bookCounts}</td>
<td>${book.detail}</td>
<td>
<a class="btn btn-primary btn-xs" href="${pageContext.request.contextPath}/book/toupdate?id=${book.bookID}">编辑</a>
&nbsp;&nbsp;
<a class="btn btn-danger btn-xs" href="${pageContext.request.contextPath}/book/deletebook/${book.bookID}">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

这样子这个功能就完善了:
image.png

坑点注意

在这里由于我们没有传入ID,所以Controller捕获到的books对象中bookID为null,这样会报错,因为int无法为null,因此会报错,我们要将bookID属性改为integer:
image.png

SSM整合:修改和删除书籍功能

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@GetMapping("/toupdate")
public String toupdatebook(Model model,int id){
Books book = bookService.SelectBookById(id);
model.addAttribute("book",book);
return "updatebook";
}
@PostMapping("/updatebook")
public String updatebook(Books books){
System.out.println(books);
bookService.UpdateBook(books);
return "redirect:/book/allbooks";
}
@RequestMapping("/deletebook/{id}")
public String deletebook(@PathVariable int id){
bookService.DelBook(id);
return "redirect:/book/allbooks";
}

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
<%--
Created by IntelliJ IDEA.
User: 22927
Date: 2023/2/3
Time: 19:52
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<title>更新书籍信息</title>
</head>
<body>
<div>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">新建部门</h3>
</div>
<div class="panel-body">
<form action="${pageContext.request.contextPath}/book/updatebook" method="post">
<div class="form-group">
<input type="hidden" name="bookID" value="${book.bookID}">
</div>
<div class="form-group">
<label >书籍名称</label>
<input type="text" class="form-control" placeholder="书籍名称" name="bookName" required="required" value="${book.bookName}">
</div>
<div class="form-group">
<label >书籍数量</label>
<input type="text" class="form-control" placeholder="书籍数量" name="bookCounts" required="required" value="${book.bookCounts}">
</div>
<div class="form-group">
<label >书籍详情</label>
<input type="text" class="form-control" placeholder="书籍详情" name="detail" required="required" value="${book.detail}">
</div>
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
</div>
</div>
</body>
</html>

然后再allbooks界面加上进入删除和修改的入口:

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
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 22927
Date: 2023/2/2
Time: 22:19
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<title>书籍展示</title>
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>书籍列表 ———— 显示所有数据</small>
</h1>
</div>
</div>
</div>
<%--添加书籍界面--%>
<div class="row">
<div class="col-md-4 column">
<a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toaddbook">新增书籍</a>
</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>
</tr>
</thead>
<tbody>
<c:forEach var="book" items="${books}">
<tr>
<td>${book.bookID}</td>
<td>${book.bookName}</td>
<td>${book.bookCounts}</td>
<td>${book.detail}</td>
<td>
<%-- 编辑和删除功能--%>
<a class="btn btn-primary btn-xs" href="${pageContext.request.contextPath}/book/toupdate?id=${book.bookID}">编辑</a>
&nbsp;&nbsp;
<a class="btn btn-danger btn-xs" href="${pageContext.request.contextPath}/book/deletebook/${book.bookID}">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

之后功能就完善了:
image.png

SSM整合:查询功能

Controller:

1
2
3
4
5
6
7
@RequestMapping("/querybook")
public String querybook(String queryBookName,Model model){
System.out.println(queryBookName);
List<Books> books = bookService.SelectBookByLike(queryBookName);
model.addAttribute("books",books);
return "allbooks";
}

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
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 22927
Date: 2023/2/2
Time: 22:19
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<title>书籍展示</title>
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>书籍列表 ———— 显示所有数据</small>
</h1>
</div>
</div>
</div>
<%--添加书籍界面--%>
<div class="row">
<div class="col-md-4 column">
<a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toaddbook">新增书籍</a>
<%--回到主界面--%>
<a class="btn btn-primary" href="${pageContext.request.contextPath}/book/allbooks">书籍展示界面</a>
</div>
</div>
<%--搜索框界面--%>
<div class="col-md-4 column"></div>
<div class="col-md-4 column"></div>
<div class="col-md-4 column">
<form action="${pageContext.request.contextPath}/book/querybook" method="post" class="form-inline" style="float: right">
<input type="text" name="queryBookName" class="form-control" placeholder="请输入你要查询的书籍名称">
<input type="submit" value="查询" class="btn btn-primary">
</form>
</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>
</tr>
</thead>
<tbody>
<c:forEach var="book" items="${books}">
<tr>
<td>${book.bookID}</td>
<td>${book.bookName}</td>
<td>${book.bookCounts}</td>
<td>${book.detail}</td>
<td>
<%-- 编辑和删除功能--%>
<a class="btn btn-primary btn-xs" href="${pageContext.request.contextPath}/book/toupdate?id=${book.bookID}">编辑</a>
&nbsp;&nbsp;
<a class="btn btn-danger btn-xs" href="${pageContext.request.contextPath}/book/deletebook/${book.bookID}">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

其实html界面用的还是之前allbooks的,只不过我们改了查询语句,这次我们用的是模糊查询,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.boogipop.mapper;

import com.boogipop.pojo.Books;

import java.util.List;
import java.util.Map;

public interface BooksMapper {
//增加
Boolean AddBook(Books book);
//删除
Boolean DelBook(int id);
//修改
Boolean UpdateBook(Books books);
//查询所有
List<Books> SelectAllBooks();
//查询某一本书
Books SelectBookById(int id);
//模糊查询
List<Books> SelectBookByLike(String queryname);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.boogipop.service;

import com.boogipop.pojo.Books;

import java.util.List;
import java.util.Map;

public interface BookService {
//增加
Boolean AddBook(Books book);
//删除
Boolean DelBook(int id);
//修改
Boolean UpdateBook(Books books);
//查询所有
List<Books> SelectAllBooks();
//查询某一本书
Books SelectBookById(int id);
List<Books> SelectBookByLike(String queryname);
}

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
package com.boogipop.service;

import com.boogipop.mapper.BooksMapper;
import com.boogipop.pojo.Books;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
@Component
public class BookServiceImpl implements BookService{
@Autowired
private BooksMapper booksMapper;
@Override
public Boolean AddBook(Books book) {
return booksMapper.AddBook(book);
}

@Override
public Boolean DelBook(int id) {
return booksMapper.DelBook(id);
}

@Override
public Boolean UpdateBook(Books books) {
return booksMapper.UpdateBook(books);
}

@Override
public List<Books> SelectAllBooks() {
return booksMapper.SelectAllBooks();
}

@Override
public Books SelectBookById(int id) {
return booksMapper.SelectBookById(id);
}

@Override
public List<Books> SelectBookByLike(String queryname) {
return booksMapper.SelectBookByLike(queryname);
}
}

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" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.boogipop.mapper.BooksMapper">
<select id="SelectAllBooks" resultType="Books">
select * from books
</select>
<select id="SelectBookById" resultType="Books" parameterType="int">
select * from books where bookID=#{id}
</select>
<insert id="AddBook" parameterType="Books">
insert into books(bookName,bookCounts,detail) values (#{bookName},#{bookCounts},#{detail})
</insert>
<update id="UpdateBook" parameterType="Books">
update books set bookName=#{bookName},bookCounts=#{bookCounts},detail=#{detail} where bookID=#{bookID}
</update>
<delete id="DelBook" parameterType="int">
delete from books where bookID=#{id};
ALTER TABLE books AUTO_INCREMENT = 1;
</delete>
<select id="SelectBookByLike" parameterType="String" resultType="Books">
select * from books where bookName like concat("%",#{querybookname},"%")
</select>
</mapper>

问题总结

在整合的过程中肯定遇到了一些问题:

Ajax

其实这个不想多讲的,因为没啥好说的,就是jquery的一些用法

SSM整合:登录拦截

这里我觉得狂神讲的可能不太好,因此打算自己写写试试,首先我们先来介绍一下SpringMVC中的拦截器是什么:
其实在Struct2中也有拦截器这一个概念(struct2是个啥远古东西),SpringMVC中也有,你可以理解为和Filter一样,也是对我们的请求进行拦截,我们接下来就用一个小Demo来测试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.boogipop.Interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle in");
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandler in");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterHandler in");
}
}

我们将我们自定义类继承HandlerInterceptor接口即可,和Filter一样,之后重写他的方法,在这里放行是通过preHandlereturn true来实现的,如果return false,那么就不会进入posthandle和afterhandle之中,随后我们需要在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:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--将mapper整合进来-->
<import resource="ApplicationContext.xml"/>
<import resource="mapperbean.xml"/>
<import resource="servicebean.xml"/>
<!--包扫描-->
<context:component-scan base-package="com.boogipop.controller"/>
<!-- 静态资源过滤-->
<mvc:default-servlet-handler/>
<!-- 注解驱动,静态资源过滤会导致注解驱动失效,因此必须补上-->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 拦截器设置-->
<mvc:interceptors>
<mvc:interceptor>
<!--表示匹配所有请求-->
<mvc:mapping path="/**"/>
<bean class="com.boogipop.Interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>

这样一个简单的拦截器就完成了,之后我们写一个测试的requestmapping即可:
image.png

访问接口,发现拦截成功,这一过程与AOP横切似乎有点类似,但不完全是,那么接下来我们需要写一个登录功能,我们遵从由内到外的原则,也就是先写底层controller,再去编写前端view视图,在这一过程我们需要写controller和Interceptor,以及Model(数据库):
首先我们先创建一张用户表吧:
image.png
那么随之而来的就是pojo类和Mapper类了:

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
package com.boogipop.pojo;

import org.apache.ibatis.type.Alias;

@Alias("User")
public class User {
private Integer id;
private String username;
private String password;

public User(String username, String password) {
this.username = username;
this.password = password;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}

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;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public User() {
}

public User( String username, String password,Integer id) {
this.id = id;
this.username = username;
this.password = password;
}
}

1
2
3
4
5
6
7
8
9
package com.boogipop.mapper;

import com.boogipop.pojo.User;

public interface UserMapper {
Boolean Register(User user);
User SelectUserByName(String name);
}

1
2
3
4
5
6
7
8
9
10
11
<?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.boogipop.mapper.UserMapper">
<insert id="Register" parameterType="User">
insert into user(username,password) values (#{username},#{password})
</insert>
<select id="SelectUserByName" parameterType="String" resultType="User">
select * from user where username=#{username}
</select>
</mapper>

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
70
package com.boogipop.controller;

import com.boogipop.pojo.Books;
import com.boogipop.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.List;

@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
@Qualifier("bookServiceImpl")
private BookService bookService;
@RequestMapping("/allbooks")
public String booklist(Model model){
List<Books> books = bookService.SelectAllBooks();
model.addAttribute("books",books);
return "allbooks";

}
@RequestMapping("/toaddbook")
public String toaddbook(Model model){
return "addbook";
}
@PostMapping("/addbook")
public String addbook(Model model,Books books) throws Exception {
Boolean add = bookService.AddBook(books);
if(add){
System.out.println("add successfully");
}
else{
throw new Exception("添加错误");
}
return "redirect:/book/allbooks";
}
@GetMapping("/toupdate")
public String toupdatebook(Model model,int id){
Books book = bookService.SelectBookById(id);
model.addAttribute("book",book);
return "updatebook";
}
@PostMapping("/updatebook")
public String updatebook(Books books){
System.out.println(books);
bookService.UpdateBook(books);
return "redirect:/book/allbooks";
}
@RequestMapping("/deletebook/{id}")
public String deletebook(@PathVariable int id){
bookService.DelBook(id);
return "redirect:/book/allbooks";
}
@RequestMapping("/querybook")
public String querybook(String queryBookName,Model model){
System.out.println(queryBookName);
List<Books> books = bookService.SelectBookByLike(queryBookName);
model.addAttribute("books",books);
return "allbooks";
}
@RequestMapping("/index")
public String index() {
return "index";
}
}

Inceptor:

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
package com.boogipop.Interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
String username= (String) session.getAttribute("username");
if(username!=null){
return true;
}
else {
response.sendRedirect("/user/login");
return false;
}
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

}
}

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:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--将mapper整合进来-->
<import resource="ApplicationContext.xml"/>
<import resource="mapperbean.xml"/>
<import resource="servicebean.xml"/>
<!--包扫描-->
<context:component-scan base-package="com.boogipop.controller"/>
<!-- 静态资源过滤-->
<mvc:default-servlet-handler/>
<!-- 注解驱动,静态资源过滤会导致注解驱动失效,因此必须补上-->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 拦截器设置-->
<mvc:interceptors>
<mvc:interceptor>
<!--表示匹配所有请求-->
<mvc:mapping path="/book/**"/>
<bean class="com.boogipop.Interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>

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
<!DOCTYPE html>
<%@ page contentType="text/html; charset=utf-8"%>
<%@ page isELIgnored="false" %>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图书管理系统登录界面</title>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<div class="box">
<h2>Login</h2>
<form action="${pageContext.request.contextPath}/user/login" method="post">
<div class="input-box">
<label>账号</label>
<input type="text" name="username"/>
</div>
<div class="input-box">
<label>密码</label>
<input type="password" name="password"/>
<span style="color: white;font-size: small">${msg}</span>
</div>
<div class="btn-box">
<a href="#">忘记密码?</a>
<div>
<button type="submit" value="login">登录</button>
<%-- 无下划线--%>
<button><a href="${pageContext.request.contextPath}/user/register" style="color: white;text-decoration: none" >注册</a></button>
</div>
</div>
</form>
</div>

<script type="text/javascript">

</script>
</body>
</html>
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
<!DOCTYPE html>
<%@ page contentType="text/html; charset=utf-8"%>
<%@ page isELIgnored="false" %>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户注册界面</title>
<link rel="stylesheet" href="/static/css/registerstyle.css">
</head>
<body>
<div class="box">
<h2>Login</h2>
<form action="${pageContext.request.contextPath}/user/register" method="post">
<div class="input-box">
<label>账号</label>
<input type="text" name="username"/>
</div>
<div class="input-box">
<label>密码</label>
<input type="password" name="password"/>
<span style="color: white;font-size: small">${msg}</span>
</div>
<div class="btn-box">
<a href="#">什么?在想我的事情?</a>
<div>
<button type="submit" value="login">提交注册</button>
<%-- 无下划线--%>
<button><a href="${pageContext.request.contextPath}/user/login" style="color: white;text-decoration: none" >登录</a></button>
</div>
</div>
</form>
</div>

<script type="text/javascript">

</script>
</body>
</html>

坑点小结

首先是遇到错误Error attempting to get column 'username' from result set的解决方法,这个是因为pojo类没有无参构造方法,假如不要无参构造方法的话,你有参构造方法中形参的排序和类型一定要和数据库字段保持一致,否则报错:

SpringMVC文件上传

SpringMVC文件下载

小结

那到这里SpringMVC也算是正式结束了,开发这东西果然会上瘾的,寒假学了Spring、mybatis、springmvc,感觉也是获得了挺多东西的,再接再厉

About this Post

This post is written by Boogipop, licensed under CC BY-NC 4.0.

#开发