Maven创建子项目卡住 这个问题是镜像没配置好的原因 参考JavaWeb的解决方法
MVC架构 什么是MVC架构?MVC是Model、View、Controller 的缩写,他们三者的意思分别为:
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 > <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 > <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种情况: 在这里首先利用到Servlet去对请求做处理和转发,然后在jsp中我们用el表达式获取了msg这个变量,在这里就先讲一下el表达式
EL表达式 EL 全名为Expression Language。EL主要作用:
获取数据
执行运算
获取web开发常用对象
调用java方法
使用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表达式取出来了,也可以使用如下方法获取各个域中的属性
例子就全部看博客吧
注意事项 EL表达式是JSP 2.0规范中的一门技术 。因此,若想正确解析EL表达式,需使用支持Servlet2.4/JSP2.0技术的WEB服务器。 注意:有些Tomcat服务器如不能使用EL表达式 (1)升级成tomcat6 (2)在JSP中加入<%@ page isELIgnored=”false” %>
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 > <servlet > <servlet-name > springmvc</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
然后需要配置springmvc配置文件
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 > <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 (); mv.addObject("msg" ,"HelloSpringMVC" ); mv.setViewName("test" ); 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的例子一样 这就是一个简单的小案例
简单分析 在这/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跳转的界面: DispacherServlet就是在Web.xml中注册的唯一servlet,在SpringMVC中,任何路由都经过它的处理进行跳转,相当于一个中央控制器,我们跟进它的源码可以发现,它实际上就是HttpServlet的一个封装:
错误排查 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的执行流程如上:
客户端发送请求,到达DispacherServlet,解析请求对应的handler,在这里我们选择的映射器为BeanNameUrlHandlerMapping
看名字就知道这是根据bean的id来设置对应的路由,比如我们第一个程序中的/hello
解析到对应的handler后,开始由HandlerAdapter
适配器来处理
HanlderAdapter会根据Handler来处理对应的请求,并处理相关业务逻辑
处理器处理完业务后,返回一个ModelAndView对象,Model是返回的数据对象,View是视图
ViewResolver会根据逻辑View查找实际的View(jsp/test.jsp)
DispacherServlet把返回的Model传给View
通过View返回请求者
使用注解开发SpringMVC 使用注解进行开发就有点像Flask和SpringBoot了,很方便,实在是方便,在这之前又发现了一个问题:https://blog.csdn.net/zhangphil/article/details/127134127 解决方法如上,有效,诶妈的,框架这些弯钩东西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 > <servlet > <servlet-name > springmvc</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
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功能,为什么没加上之前的几个适配器和映射器呢? 我们之前加这些其实是为了解释原理,在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
注解,只是在不同的层称呼不同
@Controller 控制器(注入服务) 用于标注控制层,相当于struts中的action层
@Service 服务(注入dao) 用于标注服务层,主要用来进行业务的逻辑处理
@Repository(实现dao访问) 用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件
@Component (把普通pojo实例化到spring容器中,相当于配置文件中的 )
同样很好理解,@RequestMapping
注解就是用来设置路由的,然后这我们就没有继承Controllor接口了,这里直接传入一个Model对象,这个model就和之前的ModelandView
对象一样,效果是相同的 最后还有一点,requestmapping下函数返回值为String时,会进行页面跳转,比如这里就会跳转到/jsp/hello.jsp
,和之前说的也是一样的
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 > <servlet > <servlet-name > springmvc</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
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 > <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 > <servlet > <servlet-name > springmvc</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
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
注解可以用来设置路由,这个注解是放在方法上面的,但同时也可以放在一个类上: 这时加入我们还想访问到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学的很相似 这样我们就可以简单的体验一下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请求访问: 用GET访问已经不行了,我们换成POST: 完美解决问题,这里通过method = RequestMethod.POST
来指定路由的请求类型 还有一个需要注意点就是这里既然指定了method,那么前面路由也必须加一个value=
(name=是不可以的,测试过了,会报错) 这里也要指定路由的名字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即可: 经过测试成功:
这里就是对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 > </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" ; } }
这种情况下,我们的请求不会经过视图解析器,因此需要手动添加前缀和后缀: 可以看到成功跳转,接着我们把视图解析器取消注释,然后修改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关键词后会无视视图解析器,直接转发: 我们再次修改关键词为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会变化: 很简单的重定向和转发案例,理解起来轻松~
接收请求和数据回显 接收数据 在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)
在后台即可获取对应的数据,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)
那我们可不可以接受一个对象呢?答案是可以的,我们先定义一个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)
会发现: 值完全都没注入进去,这其实和Spring的Bean装配是一个道理,因此我们需要给它加上set和get方法: 加上之后就正常了
数据回显到前端 在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 (); mv.addObject("msg" ,"HelloSpringMVC" ); mv.setViewName("test" ); 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基本配置如下,我们正常传入一个中文,结果如下: 会出现乱码的问题,解决这个乱码的问题很简单,我们多加入一段代码:
1 2 3 4 request.setCharacterEncoding("UTF-8" ); response.setCharacterEncoding("UTF-8" ); response.setContentType("text/html;charset=UTF-8" ); response.getWriter().println(name);
这样即可解决 但是接受控制台参数就是会乱码,这个改不了啊啊啊啊,等以后看看能不能解决吧呜呜呜
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 { HttpServletResponse myResponse=(HttpServletResponse) response; myResponse.setContentType("text/html;charset=UTF-8" ); HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletRequest myrequest = new MyRequest (httpServletRequest); filterChain.doFilter(myrequest, response); } @Override public void destroy () { Filter.super .destroy(); } class MyRequest extends HttpServletRequestWrapper { private HttpServletRequest request; private boolean hasEncode; public MyRequest (HttpServletRequest request) { super (request); this .request = request; } @Override public Map getParameterMap () { String method = request.getMethod(); if (method.equalsIgnoreCase("post" )) { try { request.setCharacterEncoding("utf-8" ); return request.getParameterMap(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else if (method.equalsIgnoreCase("get" )) { Map<String, String[]> parameterMap = request.getParameterMap(); if (!hasEncode) { for (String parameterName : parameterMap.keySet()) { String[] values = parameterMap.get(parameterName); if (values != null ) { for (int i = 0 ; i < values.length; i++) { try { 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 "我是好人" ; }
我们只需要加上produces = "text/html;charset=UTF-8"
:
JackJson、FastJson2(推荐FastJson2) 由于他妈的上面的乱码实在是给我带来了许多震撼,真的 首先JSON我反正是已经很熟悉了,我就不介绍了,我脑里还游荡者上一波的中文乱码问题,我草,真的纯畜 先讲一下JackJson吧,首先是依赖包
1 2 3 4 5 6 <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; }
以上两种方法对应的输出结果为: 符合JSON的格式规范,除此之外它还能用来对日期做转换:
1 2 3 4 5 6 @RequestMapping("/json3") @ResponseBody public String data () throws JsonProcessingException { Date date=new Date (); return new ObjectMapper ().writeValueAsString(date); }
正常来说返回值应该是一个时间戳: 这里假如我们想要将其转换为标准格式该怎么做呢,传统做法是用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 ()); }
其实我觉得都差不多,根据这个东西我们可以写一个工具类来帮我做转换,如果是普通对象那就直接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); }
输出结果与之对应,工具里面把getjson方法利用达到了最大
FastJson使用(控制台乱码破案) 首先到这里破案了,是Jdk的版本太高,之前用的是19,换成17的之后立马没问题了呜呜呜呜 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); }
其实我感觉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 > <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 > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.14.1</version > </dependency > <dependency > <groupId > com.alibaba.fastjson2</groupId > <artifactId > fastjson2</artifactId > <version > 2.0.23</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.30</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.6</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 6.0.4</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 3.0.1</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.19</version > </dependency > <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}" /> <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 > <bean id ="sqlsessionfactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="datasource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath:com/boogipop/mapper/*Mapper.xml" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <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" ); } } }
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-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}" /> <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 > <bean id ="sqlsessionfactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="datasource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath:com/boogipop/mapper/*Mapper.xml" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <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" > <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" > <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>
最后页面的效果如下! 还是比较好看的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 > <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 >
这样子这个功能就完善了:
坑点注意 在这里由于我们没有传入ID,所以Controller捕获到的books对象中bookID为null,这样会报错,因为int无法为null,因此会报错,我们要将bookID属性改为integer:
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 > <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 >
之后功能就完善了:
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 > <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 >
问题总结 在整合的过程中肯定遇到了一些问题:
删除数据后id不连续问题:1 2 3 4 <delete id ="DelBook" parameterType ="int" > delete from books where bookID=#{id}; ALTER TABLE books AUTO_INCREMENT = 1; </delete >
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&allowMultiQueries=true jdbc.username=root jdbc.password=jiayou357753
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一样,之后重写他的方法,在这里放行 是通过preHandle
中return 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" > <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即可:
访问接口,发现拦截成功,这一过程与AOP横切似乎有点类似,但不完全是,那么接下来我们需要写一个登录功能,我们遵从由内到外的原则,也就是先写底层controller,再去编写前端view视图,在这一过程我们需要写controller和Interceptor,以及Model(数据库): 首先我们先创建一张用户表吧: 那么随之而来的就是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" > <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,感觉也是获得了挺多东西的,再接再厉