SpringMVC是什么?
Spring MVC 是 Spring 框架中的一个模块,用于构建基于 MVC(Model-View-Controller)设计模式的 Web 应用程序。它分离了应用程序的业务逻辑、用户界面和用户输入,使开发更加模块化和易于维护。
核心组件
- Model:负责封装应用数据,通常与业务逻辑交互。
- View:负责渲染数据,生成用户界面(如 JSP、Thymeleaf)。
- Controller:处理用户请求,调用业务逻辑并返回视图。
优点
- 松耦合:各组件职责明确,易于维护。
- 灵活性:支持多种视图技术。
- 集成性:与 Spring 框架无缝集成,方便使用其他功能(如事务、安全)。
构建基础环境
先导入依赖
<!-- 使用 Jakarta Servlet API --><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>6.0.0</version><scope>provided</scope></dependency><!-- 使用 Jakarta JSTL API --><dependency><groupId>jakarta.servlet.jsp.jstl</groupId><artifactId>jakarta.servlet.jsp.jstl-api</artifactId><version>3.0.2</version></dependency><!-- JSTL 实现 --><dependency><groupId>org.glassfish.web</groupId><artifactId>jakarta.servlet.jsp.jstl</artifactId><version>3.0.1</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.2.3</version></dependency>
简单写一个Servlet
package com.myLearning;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;public class HelloServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getParameter("method");if(method.equals("add")) {req.getSession().setAttribute("msg", "执行add方法");}else{req.getSession().setAttribute("msg","执行了不知所谓的方法");}// 转发请求req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req, resp);}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}
}
创建/WEB-INF/jsp/test.jsp,并写一个简单的页面
<html>
<head><title>测试</title>
</head>
<body>${msg}
</body>
</html>
简单写一个主页hello.jsp
<html>
<head><title>hello</title>
</head>
<body>
<form action="/test" method="post">method:<input type="text" name="method"/><input type="button" value="submit" onclick="submit()">
</form>
</body>
</html>
在web.xml中配置
<?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"><session-config><session-timeout>15</session-timeout></session-config><welcome-file-list><welcome-file>hello.jsp</welcome-file></welcome-file-list><servlet><servlet-name>testServlet</servlet-name><servlet-class>com.myLearning.HelloServlet</servlet-class></servlet><servlet-mapping><servlet-name>testServlet</servlet-name><url-pattern>/test</url-pattern></servlet-mapping>
</web-app>
最后配置好tomcat,启动即可访问
SpringMVC的具体执行流程
用户请求 -> DispatcherServlet -> HandlerMapping -> HandlerExecutionChain -> HandlerAdapter -> Controller -> ModelAndView -> ViewResolver -> View -> 渲染响应 -> 返回用户
-
用户发送请求
用户通过浏览器发起 HTTP 请求,请求被发送到 Spring MVC 的前端控制器DispatcherServlet
。 -
DispatcherServlet 接收请求
DispatcherServlet
是 Spring MVC 的核心组件,负责接收所有的请求。 -
HandlerMapping 查找处理器
DispatcherServlet
调用HandlerMapping
,根据请求的 URL 查找对应的处理器(Controller
或Handler
)。HandlerMapping
返回一个HandlerExecutionChain
,包含处理器和可能的拦截器。
-
HandlerAdapter 调用处理器
DispatcherServlet
通过HandlerAdapter
调用处理器(Controller
或Handler
)。HandlerAdapter
的作用是适配不同类型的处理器(如基于注解的@Controller
、基于接口的Controller
实现类等)。- 常见的
HandlerAdapter
实现包括RequestMappingHandlerAdapter
(用于处理@Controller
和@RequestMapping
注解)。
-
处理器执行业务逻辑
- 处理器(
Controller
)执行业务逻辑,可能会调用 Service 层或 DAO 层。 - 处理器返回一个
ModelAndView
对象,包含模型数据(Model)和视图名称(View)。
- 处理器(
-
处理拦截器(可选)
如果配置了拦截器(HandlerInterceptor
),在处理器执行前后会调用拦截器的preHandle
和postHandle
方法。 -
视图解析(ViewResolver)
DispatcherServlet
调用ViewResolver
,根据ModelAndView
中的视图名称解析出具体的视图对象(如 JSP、Thymeleaf 等)。 -
渲染视图(View)
DispatcherServlet
将模型数据传递给视图,视图根据模型数据渲染生成最终的 HTML 内容。 -
返回响应
渲染后的视图内容通过DispatcherServlet
返回给客户端(浏览器),完成整个请求-响应流程。
先来简单写一个基于SpringMVC的程序
先配置web.xml
<?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"><session-config><session-timeout>15</session-timeout></session-config><welcome-file-list><welcome-file>hello.jsp</welcome-file></welcome-file-list><!--1.注册DispatcherServlet--><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!--启动级别-1--><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>
编写一个HelloController.java
package com.myLearning.controller;import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;//注意:这里我们先导入Controller接口
public class HelloController implements Controller {public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {//ModelAndView 模型和视图ModelAndView mv = new ModelAndView();//封装对象,放在ModelAndView中。Modelmv.addObject("msg","HelloSpringMVC!");//封装要跳转的视图,放在ModelAndView中mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jspreturn mv;}
}
创建一个配置文件springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--处理映射器--><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 处理器适配器--><bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/><!-- 视图解析器--><!--视图解析器:DispatcherServlet给他的ModelAndView--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"><!--前缀--><property name="prefix" value="/WEB-INF/jsp/"/><!--后缀--><property name="suffix" value=".jsp"/></bean><!--Handler--><bean id="/hello" class="com.myLearning.controller.HelloController"/>
</beans>
最后创建/WEB-INF/jsp/hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Hello</title>
</head>
<body>
${msg}
</body>
</html>
然后配置Tomcat,启动项目,访问http://localhost:8080/hello ,即可看到结果
现在我们使用注解来完成SpringMVC的开发
由于maven可能会有资源过滤的问题,所以我们需要在pom.xml中添加如下配置
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources>
</build>
我们依旧要配置一个web.xml
<?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"><!-- <session-config>-->
<!-- <session-timeout>15</session-timeout>-->
<!-- </session-config>--><!-- <welcome-file-list>-->
<!-- <welcome-file>hello.jsp</welcome-file>-->
<!-- </welcome-file-list>--><!--1.注册DispatcherServlet--><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!--启动级别-1--><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的配置文件springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --><context:component-scan base-package="com.myLearning.controller"/><!-- 让Spring MVC不处理静态资源 如.mp4 .html等--><mvc:default-servlet-handler /><!--支持mvc注解驱动在spring中一般采用@RequestMapping注解来完成映射关系要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例这两个实例分别在类级别和方法级别处理。而annotation-driven配置帮助我们自动完成上述两个实例的注入。--><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,来处理请求
在其中我们需要使用@Controller注解来标识这个类是一个controller,并且使用@RequestMapping注解来指定这个controller的访问路径
package com.myLearning.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/HelloController")
public class HelloController {//真实访问地址 : 项目名/HelloController/hello@RequestMapping("/hello")public String sayHello(Model model){//向模型中添加属性msg与值,可以在JSP页面中取出并渲染model.addAttribute("msg","hello,SpringMVC");//web-inf/jsp/hello.jspreturn "hello";}
}
确保/WEB-INF/jsp/目录下有hello.jsp文件,我们上面编写过
最后我们配置好tomcat服务器,启动项目,访问http://localhost:8080/HelloController/hello ,就可以看到我们编写的页面了
编写Controller的两种方式
经过上面两种方式的程序编写,我们现在总结一下Controller的两种编写方式:
1.实现Controller接口
2.使用注解@Controller标识,在类中定义处理请求的方法,并使用@RequestMapping等注解来映射请求的URL
实现Controller接口
实现Controller接口,需要重写handleRequest方法,该方法返回一个ModelAndView对象。
package com.myLearning.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 {@Overridepublic ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {ModelAndView mv = new ModelAndView();//向模型中添加属性msg与值,可以在JSP页面中取出并渲染mv.addObject("msg","hello,SpringMVC");//web-inf/jsp/hello.jspmv.setViewName("hello");return mv;}
}
编写完后,我们还需要在springmvc.xml中配置我们的Controller
<!--配置Controller-->
<bean name="/hello" class="com.myLearning.controller.HelloController"/>
使用注解@Controller标识
使用@Controller注解标识该类为处理请求的Controller,通过@RequestMapping注解设置请求的路径。
package com.myLearning.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/HelloController")
public class HelloController {//真实访问地址 : 项目名/HelloController/hello@RequestMapping("/hello")public String sayHello(Model model){//向模型中添加属性msg与值,可以在JSP页面中取出并渲染model.addAttribute("msg","hello,SpringMVC");//web-inf/jsp/hello.jspreturn "hello";}
}
然后,我们需要在springmvc.xml中配置扫描包即可
<!--扫描包-->
<context:component-scan base-package="com.myLearning.controller"/>
Restful风格
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
功能
资源:互联网所有的事物都可以抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、删除、修改、查询。
传统方式操作资源
通过不同的参数来实现不同的效果!方法单一,都是get。
http://127.0.0.1/item/queryItem.action?id=1 查询,GET
http://127.0.0.1/item/saveItem.action 新增,POST
使用RESTful操作资源
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
使用Restful风格优化代码
那么我们如何获取restful风格中传递的参数呢?请看下面的示例:
我们先编写一个/Web-INF/jsp/test1.jsp页面用于测试:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>test1</title>
</head>
<body>
计算结果为:${rst}
${msg}
</body>
</html>
然后我们创建一个新的controller类,在这个类中,我们指明访问路径,以及路径中的参数名用于获取从路径中传递的参数:
package com.myLearning.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class Controller2 {
// 在定义时,我们可以指定对应位置映射的参数名@RequestMapping("/t1/{a}/{b}")
// 我们可以在参数中指明我们将要从路径的哪个参数名中获取对应参数public String test1(@PathVariable("a") int a, @PathVariable("b") int b, Model model) {model.addAttribute("rst",a + b);model.addAttribute("msg", "Hello World");return "test1";}
}
除了我们可以指定参数之外,我们还可以设置方法对应的请求类型,比如我们只希望这个方法处理get请求,那么我们可以这样写:
@RequestMapping(value = "/t1/{a}/{b}", method = RequestMethod.GET)
同理,可以设置method为POST,PUT,DELETE等,用于处理不同类型的请求。
还有另一种形式可以指定请求的类型:
@GetMapping("/t1/{a}/{b}")
这种形式是用于指定处理Get类型请求的的简写形式,类似的表达还有@PostMapping, @PutMapping, @DeleteMapping
SpringMVC中的结果跳转
一般方式
在一般情况下,我们让SpringMVC通过我们返回的视图名称,以及经过视图解析器处理后,得到我们最后要跳转的页,如:
在SpringMVC配置文件中设置视图解析器:
<!-- 视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" /></bean>
然后我们就可以在方法中返回视图名称,交由视图解析器处理,如:
@RequestMapping("/t1/{a}/{b}")
public String test1(@PathVariable("a") int a, @PathVariable("b") int b, Model model) {model.addAttribute("rst",a + b);model.addAttribute("msg", "Hello World");return "test1";
}
使用Servlet API方式
我们也可以在方法中获取Servlet 中使用的变量,并使用其API
完成转发
@GetMapping("/t1/{a}/{b}")public void test1(@PathVariable("a") int a, @PathVariable("b") int b, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, ServletException, IOException {request.setAttribute("rst",a + b);request.setAttribute("msg", "Hello World!!!");// 使用Servlet API进行转发request.getRequestDispatcher("/WEB-INF/jsp/test1.jsp").forward(request, response);}
完成重定向
@GetMapping("/t1/{a}/{b}")public void test1(@PathVariable("a") int a, @PathVariable("b") int b, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, ServletException, IOException {request.setAttribute("rst",a + b);request.setAttribute("msg", "Hello World!!!");// 使用Servlet API进行重定向response.sendRedirect(request.getContextPath() + "/hello.jsp");}
在没有视图解析器的情况下,我们也可以通过返回字符串的方式完成转发和重定向
完成转发
@GetMapping("/t1/{a}/{b}")public String test2(@PathVariable("a") int a, @PathVariable("b") int b,Model model) {// 无视图解析器完成转发return "forward:/hello.jsp";}
完成重定向
@GetMapping("/t1/{a}/{b}")public String test2(@PathVariable("a") int a, @PathVariable("b") int b,Model model) {// 无视图解析器完成重定向return "redirect:/hello.jsp";}
在有视图解析器的情况下,完成重定向和转发
完成重定向
@GetMapping("/t1/{a}/{b}")public String test2(@PathVariable("a") int a, @PathVariable("b") int b,Model model) {// 有视图解析器完成重定向return "redirect:/hello.jsp";}
完成转发
@GetMapping("/t1/{a}/{b}")public String test2(@PathVariable("a") int a, @PathVariable("b") int b,Model model) {// 有视图解析器完成转发return "hello";}
SpringMVC处理提交数据
我们通常会在请求中附带额外的参数数据,如:http://localhost:8080/hello?name=张三&age=18,除此之外还会有类似username,password等数据,我们如何获取这些数据呢?
当我们要接收一个非对象数据时
我们可以使用@RequestParam注解来获取传递的参数
假设我们有一个请求,请求地址为:http://localhost:8080/test1?name=jack
我们可以通过如下方式获取到name的值:
@RequestMapping("/test1")public String test3(@RequestParam("name") String name, Model model) {System.out.println(name);return "hello";}
当我们接收一个实体类对象时
我们可以直接将实体类对象作为方法参数,SpringMVC会自动将请求中的参数封装到实体类对象中
假设我们有一个实体类User,如下:
package com.myLearning.pojo;import org.apache.ibatis.type.Alias;import java.io.Serializable;@Alias("user")
public class User implements Serializable {private int id;private String name;private String pwd;public User() {}public User(int id, String name, String pwd) {this.id = id;this.name = name;this.pwd = pwd;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", pwd='" + pwd + '\'' +'}';}
}
并且假设我们的url为:http://localhost:8080/test1?name=jack&pwd=123456&id=1
我们可以通过以下方式获取参数:
@RequestMapping("/test1")public String test3(User user, Model model) {System.out.println(user);return "hello";}
Model与ModelMap
这二者都是用于向前端视图页面传递数据的,ModelMap继承了LinkedHashMap,具有LinkedHashMap的所有方法,而Model是精简版,我们大部分时间使用Model即可。
乱码问题
如果前端传递的数据中包括中文,如: 张三、李四、利姆露等,那么我们在处理的时候可能会出现乱码问题,这个时候,我们可以通过以下方式解决:
使用Spring提供的编码过滤器
在web.xml中添加以下代码:
<filter><filter-name>encoding</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>encoding</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
还可以修改tomcat的配置文件
在tomcat的conf/server.xml中设置以下代码:
<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" URIEncoding="UTF-8"/>
JSON
什么是JSON?
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的一个子集,但独立于编程语言,广泛用于Web应用中的数据交换。其本质其实就是一个字符串,只不过这个字符串的格式比较特殊,符合一定的规则。
JSON的特点:
-
轻量级:JSON格式简洁,数据量小,适合网络传输。
-
易读性:结构清晰,便于人类阅读和理解。
-
独立性:不依赖特定语言,几乎所有编程语言都支持JSON。
-
数据结构:支持对象(键值对)和数组(有序列表)两种主要结构。
JSON和Javascript对象的转换
JSON和JavaScript对象之间的转换是JSON数据在Web应用中常用的操作。在JavaScript中,可以使用内置的JSON对象来进行转换。
JSON字符串转换为JavaScript对象
使用JSON.parse()
方法可以将JSON字符串转换为JavaScript对象。
var jsonString = '{"name":"John", "age":30, "city":"New York"}';
var jsonObject = JSON.parse(jsonString);
console.log(jsonObject.name); // 输出 "John"
JavaScript对象转换为JSON字符串
使用JSON.stringify()
方法可以将JavaScript对象转换为JSON字符串。
javascript
var jsonObject = {name: "John", age: 30, city: "New York"};
var jsonString = JSON.stringify(jsonObject);
console.log(jsonString); // 输出 '{"name":"John","age":30,"city":"New York"}'
使用Controller返回JSON数据
使用Jackson完成JSON转换
首先我们需要添加Jackson的依赖:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.18.3</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.18.3</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.18.3</version></dependency>
然后我们编写一个controller类,用于返回JSON数据:
package com.myLearning.controller;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myLearning.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class Controller1 {@RequestMapping("/json1")@ResponseBody//@ResponseBody注解,指定返回的结果不走视图解析器,而是直接作字符串返回public String json1() throws JsonProcessingException {//创建一个jackson的对象映射器,用来解析数据ObjectMapper mapper = new ObjectMapper();//创建一个对象User user = new User(1,"利姆露","666666");//将我们的对象解析成为json格式String str = mapper.writeValueAsString(user);//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便return str;}
}
解决乱码问题
测试时,我们会发现显示有乱码问题,此时我们可以通过设置@RequestMaping的produces属性来实现:
package com.myLearning.controller;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myLearning.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class Controller1 {
// 我们设置了其produces的属性@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")@ResponseBody//@ResponseBody注解,指定返回的结果不走视图解析器,而是直接作字符串返回public String json1() throws JsonProcessingException {//创建一个jackson的对象映射器,用来解析数据ObjectMapper mapper = new ObjectMapper();//创建一个对象User user = new User(1,"利姆露","666666");//将我们的对象解析成为json格式String str = mapper.writeValueAsString(user);//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便return str;}
}
除此之外,我们还可以在springmvc.xml中配置消息转换器,也可以解决乱码问题:
<!--配置消息转换器-->
<mvc:annotation-driven><mvc:message-converters register-defaults="true"><bean class="org.springframework.http.converter.StringHttpMessageConverter"><constructor-arg value="UTF-8"/></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"/></bean></property></bean></mvc:message-converters>
</mvc:annotation-driven>
现在我们已经可以成功解决乱码问题了,但是现在我们每设置一个方法返回JSON字符串,我们都需要添加@ResponseBody注解,这样显然是不方便的,所以我们可以直接在类的上方添加@RestController注解,这样就可以省略掉每个方法的@ResponseBody注解了。
package com.myLearning.controller;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myLearning.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class Controller1 {
// 我们设置了其produces的属性@RequestMapping(value = "/json1")public String json1() throws JsonProcessingException {//创建一个jackson的对象映射器,用来解析数据ObjectMapper mapper = new ObjectMapper();//创建一个对象User user = new User(1,"利姆露","666666");//将我们的对象解析成为json格式String str = mapper.writeValueAsString(user);//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便return str;}
}
输出时间格式
如果我们直接使用ObjectMapper
来输出时间的话,输出的格式默认为时间戳,即1970年到现在的毫秒数,这可能不是我们想要的,所以我们需要自定义时间格式。
@RequestMapping("/json2")public String json2() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();//不使用时间戳的方式mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);//自定义日期格式对象SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//指定日期格式mapper.setDateFormat(sdf);Date date = new Date();String str = mapper.writeValueAsString(date);return str;}
封装成工具类
我们可以发现,每次使用ObjectMapper
时都需要进行一些重复的操作,所以我们可以将其封装成一个工具类,方便我们使用。
package com.myLearning.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
public class JsonUtils {public static String getJson(Object object) {return getJson(object,"yyyy-MM-dd HH:mm:ss");}public static String getJson(Object object,String dateFormat) {ObjectMapper mapper = new ObjectMapper();//不使用时间差的方式mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);//自定义日期格式对象SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);//指定日期格式mapper.setDateFormat(sdf);try {return mapper.writeValueAsString(object);} catch (JsonProcessingException e) {e.printStackTrace();}return null;}
}
使用fastjson完成json转换
FastJSON 是阿里巴巴开源的一个高性能的 JSON 库,用于 Java 对象与 JSON 数据之间的序列化(将 Java 对象转换为 JSON 字符串)和反序列化(将 JSON 字符串转换为 Java 对象)。它是目前 Java 生态中性能最好的 JSON 库之一,广泛应用于各种 Java 项目中。
为了使用fastjson,需要在pom.xml文件中添加以下依赖:
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.56</version></dependency>
简单使用:
@RequestMapping("/json3")public String json3() throws JsonProcessingException {// 创建一个 User 对象User user = new User(1, "利姆露", "123456233333333333");// 序列化:将 User 对象转换为 JSON 字符串String jsonString = JSON.toJSONString(user);System.out.println("序列化结果:" + jsonString);// 反序列化:将 JSON 字符串转换为 User 对象User parsedUser = JSON.parseObject(jsonString, User.class);System.out.println("反序列化结果:" + parsedUser);return jsonString;}
整合SSM框架
先创建底层数据库
create database `ssmbuild`;use `ssmbuild`;create table `books`(`bookID` int(10) not null auto_increment comment 'id',`bookName` varchar(100) not null comment '书名',`bookCounts` int(10) not null comment '数量',`detail` varchar(255) not null comment '描述',key `bookID` (`bookID`)
)ENGINE=InnoDB default charset=utf8;insert into `books` (`bookID`,`bookName`,`bookCounts`,`detail`) VALUES
(1,'红楼梦',20,'理想的破灭'),
(2,'水浒传',30,'现实主义悲剧'),
(3,'c primer plus',40,'c 语言基础入门教程');
导入相关依赖
<dependencies><!-- MyBatis 核心依赖 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version> <!-- 请使用最新版本 --></dependency><!-- 数据库驱动(例如 MySQL) --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version> <!-- 请根据数据库版本选择 --></dependency><!-- JUnit 5 核心依赖 --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.10.0</version> <!-- 请使用最新版本 --><scope>test</scope></dependency><!-- JUnit 5 测试引擎 --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.10.0</version><scope>test</scope></dependency><!-- Log4j2 核心依赖 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.20.0</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.20.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.2.3</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.2.3</version></dependency><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.5</version></dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>3.0.4</version></dependency><!-- 使用 Jakarta Servlet API --><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>6.0.0</version><scope>provided</scope></dependency><!-- 使用 Jakarta JSTL API --><dependency><groupId>jakarta.servlet.jsp.jstl</groupId><artifactId>jakarta.servlet.jsp.jstl-api</artifactId><version>3.0.2</version></dependency><!-- JSTL 实现 --><dependency><groupId>org.glassfish.web</groupId><artifactId>jakarta.servlet.jsp.jstl</artifactId><version>3.0.1</version></dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.18.3</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.18.3</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.18.3</version></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.56</version></dependency> <dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.4</version></dependency></dependencies>
防止资源导出问题
在pom.xml中配置resources,防止资源导出时的问题
<!-- 在build中配置resources,防止资源导出时的问题--><build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources></build>
创建需要的软件包和资源文件
需要的软件包有:controller、service、dao、pojo
需要创建的资源配置文件:
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><typeAliases><package name="com.myLearning.pojo"/></typeAliases></configuration>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"></beans>
database.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456
创建实体类
package com.myLearning.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {private int bookID;private String bookName;private int bookCounts;private String detail;
}
创建dao接口
package com.myLearning.dao;import com.myLearning.pojo.Book;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface BookMapper {// 添加一本书int addBook(Book book);// 删除一本书int deleteBook(Book book);// 修改一本书int updateBook(Book book);// 查询所有书List<Book> getAllBooks();// 查询包含关键字的书List<Book> getBookByStr(@Param("str") String str);
}
创建BookMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--用于绑定刚刚创建的Dao(Mapper)接口-->
<mapper namespace="com.myLearning.dao.BookMapper"><insert id="addBook" parameterType="book">insert into books(`bookName`,`bookCounts`,`detail`) values(#{bookName},#{bookCounts},#{detail});
</insert><delete id="deleteBook" parameterType="book">deletefrom bookswhere `bookID` = #{bookID};
</delete><update id="updateBook" parameterType="book">update booksset `bookName` = #{bookName},`bookCounts` = #{bookCounts},`detail` = #{detail}where `bookID` = #{bookID};
</update><select id="getAllBooks" resultType="book">select * from books;</select><select id="getBookByStr" parameterType="String" resultType="book">select * from books where`bookName` like concat('%',#{str},'%')</select></mapper>
在mybatis-config.xml中配置mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//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.myLearning.pojo"/></typeAliases><mappers><mapper class="com.myLearning.dao.BookMapper"/></mappers>
</configuration>
创建service接口
package com.myLearning.service;import com.myLearning.pojo.Book;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface BookService {// 添加一本书int addBook(Book book);// 删除一本书int deleteBook(Book book);// 修改一本书int updateBook(Book book);// 查询所有书List<Book> getAllBooks();// 查询包含关键字的书List<Book> getBookByStr( String str);
}
创建service实现类(本质就是在调用dao层的接口)
package com.myLearning.service;import com.myLearning.dao.BookMapper;
import com.myLearning.pojo.Book;import java.util.List;public class BookServiceImpl implements BookService {private BookMapper bookMapper;public BookMapper getBookMapper() {return bookMapper;}public void setBookMapper(BookMapper bookMapper) {this.bookMapper = bookMapper;}@Overridepublic int addBook(Book book) {return bookMapper.addBook(book);}@Overridepublic int deleteBook(Book book) {return bookMapper.deleteBook(book);}@Overridepublic int updateBook(Book book) {return bookMapper.updateBook(book);}@Overridepublic List<Book> getAllBooks() {return bookMapper.getAllBooks();}@Overridepublic List<Book> getBookByStr(String str) {return bookMapper.getBookByStr(str);}
}
创建spring-dao.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!--关联数据库配置文件--><context:property-placeholder location="classpath:database.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}"/><property name="maxPoolSize" value="30"/><property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit--><property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间--><property name="checkoutTimeout" value="10000"/>
<!-- 获取连接失败重试次数--><property name="acquireRetryAttempts" value="2"/>
</bean><!-- sqlSessionFactory--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/>
<!-- 绑定mybatis的配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/></bean><!-- 配置dao接口扫描包,动态实现Dao接口注入到Spring中--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 要扫描的dao包--><property name="basePackage" value="com.myLearning.dao"/></bean>
</beans>
创建spring-service.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 指定扫描的包,这个包下的注解会生效 --><!-- 扫描service下的包--><context:component-scan base-package="com.myLearning.service"/><context:annotation-config/><!-- 将业务类注入到Spring中--><bean id="bookServiceImpl" class="com.myLearning.service.BookServiceImpl"><property name="bookMapper" ref="bookMapper"/></bean><!-- 配置声明式事务--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><constructor-arg ref="dataSource" /></bean><!-- 配置事务通知--><tx:advice id="txAdvice" transaction-manager="transactionManager"><!-- 给哪些方法配置事务--><tx:attributes><tx:method name="*" propagation="REQUIRED"/></tx:attributes></tx:advice><!-- aop配置事务切入--><aop:config><!-- 设置切入点,给com.myLearning.mapper包内所有类中的所有方法配置事务--><aop:pointcut id="txPointCut" expression="execution(* com.myLearning.service.*.*(..))"/><!-- 设置通知--><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/></aop:config>
</beans>
同时需要在项目结构中创建一个spring的子模块,并在其中添加我们已经创建的三个spring配置文件,applicationContext.xml、spring-mvc.xml、spring-service.xml
创建spring-mvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 注解驱动--><mvc:annotation-driven/>
<!-- 静态资源过滤--><mvc:default-servlet-handler/>
<!-- 扫描宝:controller-->
<context:component-scan base-package="com.myLearning.controller"/><!-- 视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/></bean></beans>
在applicationContext.xml中导入这个配置文件
<import resource="classpath:spring-mvc.xml"/>
在项目模块中添加web子模块,并配置web.xml
<?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"><!-- DispatchServlet--><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:applicationContext.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><!-- 乱码过滤-->
<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>
</web-app>
同时在/WEB-INF中创建jsp文件夹
创建BookController.java
现在我们已经完成了ssm的框架整合,接着我们可以为我们的网站添加功能了,首先我们需要创建一个BookController.java
package com.myLearning.controller;import com.myLearning.pojo.Book;
import com.myLearning.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("/getAllBooks")public String getAllBooks(Model model) {List<Book> books = bookService.getAllBooks();model.addAttribute("books", books);return "getAllBooks";}
}
创建index.jsp以及/WEB-INF/jsp/getAllBooks.jsp
<!--index.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>主页</title><style>a{text-decoration: none;color: cornflowerblue;font-size: 20px;}h3{width: 180px;height: 60px;margin: 100px auto;text-align: center;line-height: 60px;background: ghostwhite;}</style>
</head>
<body>
<h3><a href="${pageContext.request.contextPath}/book/getAllBooks">点击进入书籍页面</a>
</h3>
</body>
</html>
<!--/WEB-INF/jsp/getAllBooks.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>书籍展示页面</title><%-- 使用cdn引入 BootStrap 用于美化界面--%><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</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>
</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></body>
</html>
接着我们可以进一步添加功能,如添加书籍,删除书籍,修改书籍信息
首先我们修改书籍展示的页面getAllBooks.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>书籍展示页面</title><%-- 使用cdn引入 BootStrap 用于美化界面--%><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</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="col-md-4 column"><a class="btn btn-primary" href="/book/toAddBook">新增书籍</a></div><div class="col-md-8 column"><form class="d-flex justify-content-end" action="${pageContext.request.contextPath}/book/queryBook" method="post"><!-- 错误信息 --><span class="text-danger fw-bold me-2">${error}</span><!-- 输入框 --><input type="text" name="queryName" class="form-control me-2" placeholder="请输入要查询的书籍名称" /><!-- 查询按钮 --><input type="submit" class="btn btn-primary" value="查询"></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><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 href="${pageContext.request.contextPath}/book/toUpdate?bookID=${book.bookID}&bookName=${book.bookName}&bookCounts=${book.bookCounts}&detail=${book.detail}">修改</a> | <a href="${pageContext.request.contextPath}/book/deleteBook?bookID=${book.bookID}&bookName=${book.bookName}&bookCounts=${book.bookCounts}&detail=${book.detail}">删除</a></td></tr></c:forEach></tbody></table></div>
</div>
</div>
</body>
</html>
然后我们在jsp文件夹中创建一个addBook.jsp页面,用于添加书籍信息:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>添加书籍</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</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="mb-3"><label class="form-label">添加的书名</label><input type="text" name="bookName" class="form-control" required/></div><div class="mb-3"><label class="form-label">添加的数量</label><input type="text" name="bookCounts" class="form-control" required/></div><div class="mb-3"><label class="form-label">书籍相关详情</label><input type="text" name="detail" class="form-control" required/></div><button type="submit" class="btn btn-primary">添加</button></form></div>
</body>
</html>
然后我们继续在jsp文件夹下创建一个updateBook.jsp,用于更新书籍信息:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>添加书籍</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</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"><input type="hidden" name="bookID" value="${qBook.bookID}"><div class="mb-3"><label class="form-label">修改书名</label><input type="text" name="bookName" class="form-control" value="${qBook.bookName}" required/></div><div class="mb-3"><label class="form-label">修改数量</label><input type="text" name="bookCounts" class="form-control" value="${qBook.bookCounts}" required/></div><div class="mb-3"><label class="form-label">修改书籍相关详情</label><input type="text" name="detail" class="form-control" value="${qBook.detail}" required/></div><button type="submit" class="btn btn-primary">修改</button></form></div>
</body>
</html>
然后修改BookController.java文件
package com.myLearning.controller;import com.myLearning.pojo.Book;
import com.myLearning.service.BookService;
import org.apache.ibatis.annotations.Param;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;import java.util.List;@Controller
@RequestMapping("/book")
public class BookController {@Autowired@Qualifier("bookServiceImpl")private BookService bookService;@RequestMapping("/getAllBooks")public String getAllBooks(Model model) {List<Book> books = bookService.getAllBooks();model.addAttribute("books", books);return "getAllBooks";}@RequestMapping("/toAddBook")public String toAddBook(Model model) {return "addBook";}@RequestMapping("/addBook")public String addBook(Book book, Model model) {bookService.addBook(book);return "redirect:/book/getAllBooks";}@RequestMapping("/toUpdate")public String toUpdate(Book book, Model model) {model.addAttribute("qBook", book);return "updateBook";}@RequestMapping("/updateBook")public String updateBook(Book book, Model model) {bookService.updateBook(book);return "redirect:/book/getAllBooks";}@RequestMapping("/deleteBook")public String deleteBook(Book book, Model model) {bookService.deleteBook(book);return "redirect:/book/getAllBooks";}@RequestMapping("/queryBook")public String queryBook(@RequestParam("queryName") String str, Model model) {List<Book> books = bookService.getBookByStr(str);if(books.isEmpty()) model.addAttribute("error", "未找到呢,亲");model.addAttribute("books", books);return "getAllBooks";}
}
Ajax基本使用
什么是Ajax?
Ajax = Asynchronous JavaScript and XML(异步JavaScript和XML)。
Ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面。
Ajax的原理
Ajax的工作原理相当于在用户和服务器之间加了一个中间层(Ajax引擎),使用户操作与服务器响应异步化。这样把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担,从而达到节约ISP的空间和带宽租用成本的目的。
Ajax使用XMLHttpRequest对象和服务器通信,这种方式的通信在客户端和服务器之间建立了一条双向的通信渠道,服务器不再是被动的响应,而是主动向客户端推送信息。
Ajax的简单使用
jQuery为我们封装了Ajax的一些使用,让我们能够更加方便地完成ajax。
导入jQuery
为此,我们先要导入jQuery的jar包。
我们需要访问jQuery官网,https://jquery.com/download/
然后下载Download the uncompressed development version of jQuery 3.7.1
并将下载的文件jquery-3.7.1.js 放在我们项目中,假设我们放在了/WEB-INF/statics/js目录下
编写一个index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html>
<head><!-- 导入jQuery的库 --><script src="${pageContext.request.contextPath}/statics/js/jquery-3.7.1.js"></script><script>function uT(){$.post({url: "${pageContext.request.contextPath}/mySolve",data: {"username":$("#username").val()},success:function (res){$("#usernamestate").text(res);if(res==="ok"){$("#usernamestate").css("color","green")}else{$("#usernamestate").css("color","red")}}})}function pT(){$.post({url: "${pageContext.request.contextPath}/mySolve",data: {"password":$("#password").val()},success:function (res){$("#passwordstate").text(res);if(res==="ok"){$("#passwordstate").css("color","green")}else{$("#passwordstate").css("color","red")}}})}</script><title>ajax异步用户登录</title>
</head>
<body><form action="" method="post"><p>用户名:<input type="text" name="username" id="username" onblur="uT()"/> <span id="usernamestate"></span></p><p>密码: <input type="password" name="password" id="password" onblur="pT()"/> <span id="passwordstate"></span></p><input type="submit" />
</form></body>
</html>
解析:
在这个页面中,我们让用户输入它的用户名以及密码,并且在输入框失去焦点时,调用我们在javascript中的函数uT()和pT(),这两个函数分别向服务器发送请求,获取服务器返回的数据,然后根据返回的数据来改变span标签中的内容以及颜色。
在uT()以及pt()中,我们使用jQuery的post()方法向服务器发送请求,其中,url是请求的地址,data是发送的数据,success是请求成功后执行的函数,res是服务器返回的数据。在success函数中,我们根据res的值来改变span标签中的内容以及颜色。
然后我们编写一个Controller来处理这个请求:
package com.myLearning.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class testController {@RequestMapping("/mySolve")public String myResolve( @RequestParam(value = "username" ,required = false) String username,@RequestParam(value = "password" ,required = false) String password) {if(username != null){if(username.equals("admin")){return "ok";}else{return "用户名不存在";}}if(password != null){if(password.equals("123456")){return "ok";}else{return "密码不正确";}}return "error";}
}
解决乱码问题
我们此时如果直接运行我们的代码,可能会出现乱码的问题,为此我们需要在我们的sprintmvc的配置文件,假设是applicationContext.xml中添加如下配置:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="messageConverters"><list><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="defaultCharset" value="UTF-8"/></bean><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"><property name="defaultCharset" value="UTF-8"/></bean></list></property></bean>
这样就可以解决乱码的问题了
拦截器interceptor
拦截器是SpringMVC中的一种机制,它可以在请求到达目标方法之前进行一些处理,也可以在目标方法执行之后进行一些处理,它的作用类似于过滤器,但是它只能拦截请求,不能拦截静态资源,它的使用步骤如下:
- 创建一个类,实现HandlerInterceptor接口,重写preHandle、postHandle、afterCompletion方法,其中preHandle方法在目标方法执行之前执行,postHandle方法在目标方法执行之后执行,afterCompletion方法在请求完成之后执行
package com.myLearning.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 MyInterceptor implements HandlerInterceptor {@Override
// 返回true表示这个拦截器放行,返回false表示拦截这个请求public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("方法执行前,拦截器进行拦截检测");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("方法执行后");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("请求完成");}
}
- 在springmvc.xml中配置拦截器
<mvc:interceptors><mvc:interceptor>
<!-- 配置拦截器拦截的路径,/**表示所有路径--><mvc:mapping path="/**"/>
<!-- 配置我们的拦截器--><bean class="com.myLearning.interceptor.MyInterceptor"/></mvc:interceptor></mvc:interceptors>
文件上传和下载
文件上传
前端表单配置
为了实现文件上传,首先我们需要再我们的前端表单中配置enctype的属性
这个属性的默认值为application/x-www-form-urlencoded,这种情况下会将我们的值处理为url编码,而如果我们要上传文件,那么这个属性应该设置为multipart/form-data,表示将我们的表单数据以二进制的形式进行处理
<form action="/upload" enctype="multipart/form-data" method="post"><input type="file" name="file"/><input type="submit" value="upload">
</form>
在springmvc配置文件中配置bean
<!--文件上传配置--><bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
在 web.xml 中配置 Multipart 支持
<!-- DispatchServlet--><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:applicationContext.xml</param-value></init-param><load-on-startup>1</load-on-startup><multipart-config><max-file-size>10485760</max-file-size> <!-- 10MB --><max-request-size>10485760</max-request-size> <!-- 10MB --><file-size-threshold>1048576</file-size-threshold> <!-- 1MB --></multipart-config></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
controller
package com.myLearning.controller;import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;import java.io.*;@Controller
public class FileController {//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象//批量上传CommonsMultipartFile则为数组即可@RequestMapping("/upload")public String fileUpload(@RequestParam("file") MultipartFile file , HttpServletRequest request) throws IOException, IOException {//获取文件名 : file.getOriginalFilename();String uploadFileName = file.getOriginalFilename();//如果文件名为空,直接回到首页!if ("".equals(uploadFileName)){return "redirect:/index.jsp";}System.out.println("上传文件名 : "+uploadFileName);//上传路径保存设置String path = request.getServletContext().getRealPath("/upload");//如果路径不存在,创建一个File realPath = new File(path);if (!realPath.exists()){realPath.mkdir();}System.out.println("上传文件保存地址:"+realPath);InputStream is = file.getInputStream(); //文件输入流OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流//读取写出int len=0;byte[] buffer = new byte[1024];while ((len=is.read(buffer))!=-1){os.write(buffer,0,len);os.flush();}os.close();is.close();return "redirect:/index.jsp";}
}
第二种controller写法
/** 采用file.Transto 来保存上传的文件*/@RequestMapping("/upload2")public String fileUpload2(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {//上传路径保存设置String path = request.getServletContext().getRealPath("/upload");File realPath = new File(path);if (!realPath.exists()){realPath.mkdir();}//上传文件地址System.out.println("上传文件保存地址:"+realPath);//通过CommonsMultipartFile的方法直接写文件(注意这个时候)file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));return "redirect:/index.jsp";}
文件下载
controller
@RequestMapping(value="/download")public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{//要下载的图片地址String path = request.getServletContext().getRealPath("/upload");String fileName = "vertin.jpg";//1、设置response 响应头response.reset(); //设置页面不缓存,清空bufferresponse.setCharacterEncoding("UTF-8"); //字符编码response.setContentType("multipart/form-data"); //二进制传输数据//设置响应头response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));File file = new File(path,fileName);//2、 读取文件--输入流InputStream input=new FileInputStream(file);//3、 写出文件--输出流OutputStream out = response.getOutputStream();byte[] buff =new byte[1024];int index=0;//4、执行 写出操作while((index= input.read(buff))!= -1){out.write(buff, 0, index);out.flush();}out.close();input.close();return null;}
前端
<a href="/download">点击下载</a>
笔记总结于此地址
https://www.bilibili.com/video/BV1aE41167Tu?vd_source=16bf0c507e4a78c3ca31a05dff1bee4e&spm_id_from=333.788.videopod.episodes