刚开始学习SSM框架,看着各式各样的书,听着大佬们录的视频,貌似觉得很简单。但是亲自实践之后,就不会这么觉得了。
从github上拉了很多个项目下来,一个个花里胡哨,SSM框架结构命名各式各样,一个jsp网页或者java类就有成百上千行代码,而我什么都看不懂。
其实那个时候我只想搞懂SSM环境配置的逻辑,以及前端网页如何读取数据库中的数据(即前端网页显示数据库数据),因为jsp网页一旦能成功显示数据库中的数据,其他功能就可以以此类推,都是复制粘贴的事情了。
看不懂,没人教,然后面向搜索引擎的编程,最后写总结,已经是我长期以来的常态了。接着我就像做英语阅读那样,一行一行代码的去查,最后把意思串起来,得到了我的理解。当然我的理解不一定准确,欢迎大佬指正。
前端网页显示数据库数据大概分为以下八个步骤:
- 在web.xml中,使用<welcome-file-list>标签,设置默认打开的网页 /WEB-INF/views/login/test.jsp 。
- 在该前端网页 test.jsp 中增加一个按钮,按钮指向"<%=basePath%>/summary/test1.do"(<%=basePath%>后面再说)。
- 该地址被 web.xml 中的DispatcherServlet(拦截器)所拦截,只剩下 /summary/test1 。
- web.xml 将 /summary/test1 传送到 springmvc.xml ,接着springmvc.xml去扫描其管辖的包下有没有对应的controller类。
- 在controller类(后端Java类)中找到@RequestMapping(value = "/summary/test1")的方法,执行这个方法。
- 在方法中,使用model.addAttribute(),像前端页面传送从数据库读取的数据,并且返回一个字符串"login/test"。
- 返回的字符串"login/test"在springmvc.xml的配置视图解析器(ViewResolver)中,加上前缀"/WEB-INF/views/",加上后缀".jsp",即组成了一个完整的网页地址,浏览器访问的就是这个地址,即"/WEB-INF/views/login/test.jsp"。
- 前端网页 test.jsp通过 ${msg} 来获取后端发来的数据。
完整代码放在最后面,先大概讲一下每一步的逻辑思路
第一步
1. <welcome-file-list> 2. <welcome-file>/WEB-INF/views/login/test.jsp</welcome-file> 3. </welcome-file-list>
<welcome-file-list>标签字面上看起来是欢迎文件列表的意思,实际上我猜是默认加载项目的网页的意思。配置好这个,使用Tomcat运行,就会首先加载这个界面。
第二步
1. <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2. <% 3. String path = request.getContextPath(); 4. String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; 5. %> 6. <html> 7. <head> 8. <title></title> 9. </head> 10. 11. <body> 12. <a href="<%=basePath%>/summary/test1.do"> 13. <button>按钮</button> 14. </a> 15. <h2>${msg}</h2> 16. </body> 17. </html>
request.getSchema()可以返回当前页面使用的协议: http
request.getServerName()可以返回当前页面所在的服务器的名字: localhost
request.getServerPort()可以返回当前页面所在的服务器使用的端口: 8080;
request.getContextPath()可以返回当前页面所在的应用的名字.如 /views/login/
总之就是要获取到该项目的网络路径。
接着,我们使用 href="<%=basePath%>/summary/test1.do" 指向这个地址。
第三步
1. <servlet> 2. <servlet-name>dispatcherServlet</servlet-name> 3. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 4. <init-param> 5. <param-name>contextConfigLocation</param-name> 6. <param-value>classpath:spring/springmvc.xml</param-value> 7. </init-param> 8. </servlet> 9. 10. <servlet-mapping> 11. <servlet-name>dispatcherServlet</servlet-name> 12. <url-pattern>*.do</url-pattern> 13. </servlet-mapping>
DispatcherServlet就是传说中的拦截器,他能把第二步传来的 /summary/test1.do ,拦截下来,去掉后缀 .do,并且把他发送到配置文件spring.mvc。
第四步
<context:component-scan base-package="ypc.zwz.controller"/>
springmvc.xml 收到数据之后,扫描这个包下所有的类,寻找有没有和 /summary/test1 对应的方法。
第五、六步
1. package ypc.zwz.controller; 2. 3. import org.springframework.web.bind.annotation.RequestMapping; 4. import ypc.zwz.service.ArticleService; 5. 6. @Controller 7. @RequestMapping(value = "/summary") 8. public class ArticleController { 9. 10. @Autowired 11. private ArticleService articleService; 12. 13. @RequestMapping(value = "/test1") 14. public String te(@RequestParam(value = "pageCode", defaultValue = "1", required = false) int pageCode, @RequestParam(value = "pageSize", defaultValue = "3", required = false) int pageSize, HttpServletRequest request, Model model) { 15. Summary summary = articleService.findById(23); 16. String str = summary.getR_content(); 17. model.addAttribute("msg",str); 18. return "login/test"; 19. } 20. }
在ypc.zwz.controller包的ArticleController类中,找到与之对应的方法te();因为这个类@RequestMapping(value = "/summary"),类下的te方法@RequestMapping(value = "/test1"),组合起来就是 /summary/test1。所以执行这个方法。
先通过articleService.findById(23);即从Serive层读取数据库的信息(后面会给完整代码),再获取Summary类中的contnt属性,通过model.addAttribute("msg",str);方法发送至前端页面,前端页面可以通过"msg"这个键来获取到str这个值,最后向spring.mvc返回"login/test"这个字符串。
第七步
1. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 2. <property name="prefix" value="/WEB-INF/views/"/> 3. <property name="suffix" value=".jsp"/> 4. </bean>
springmvc.xml 接收到返回来的"login/test"字符串,利用试图解析器(ViewResolver)加上前缀后缀,组成完整的地址"/WEB-INF/views/login/test.jsp",返回到web.xml,浏览器正常读取打开,就正常打开。
第八步
代码见第二步,在第六步中已经说明,使用msg使用这个键来获取到str这个值,所以使用 ${msg} ,就获取到了后端传过来的str的值。
关于为什么要把原本的网址搞得这么花里胡哨,可能是为了保密吧,比如你知道主页的网页地址,那么你直接访问这个网址,就可以跳过登入了(可能是这样的吧,我猜的
登入地址XXXXX/views/login.jsp
主页地址XXXXX/views/index.jsp
那我们直接访问主页地址,就可以跳过登入了
相反现在:
登入地址XXXXX/views/login.jsp
我们需要访问XXXXXX.do这个后端方法,返回主页
但是浏览器的网页还是显示XXXXXX.do
我们不知道主页的真正地址
所以可能大概也许就起到保密的作用了。
完整代码
test.jsp 路径: WEB-INF/views/login/test.jsp
1. <%-- 2. Created by IntelliJ IDEA. 3. User: zwz 4. Date: 2020/2/17 0016 5. Time: 7:39 6. To change this template use File | Settings | File Templates. 7. --%> 8. <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9. <% 10. String path = request.getContextPath(); 11. String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; 12. %> 13. <html> 14. <head> 15. <title></title> 16. </head> 17. 18. <body> 19. <a href="<%=basePath%>/summary/test1.do"> 20. <button>按钮</button> 21. </a> 22. <h2>${msg}</h2> 23. </body> 24. </html>
web.xml 路径:WEB-INF/web.xml
1. <?xml version="1.0" encoding="UTF-8"?> 2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3. xmlns="http://xmlns.jcp.org/xml/ns/javaee" 4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 5. http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 6. version="3.1"> 7. 8. <welcome-file-list> 9. <welcome-file>/WEB-INF/views/login/test.jsp</welcome-file> 10. </welcome-file-list> 11. 12. <!--配置spring的字符编码过滤器 --> 13. <filter> 14. <filter-name>CharacterEncoding</filter-name> 15. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 16. <init-param> 17. <param-name>encoding</param-name> 18. <param-value>utf-8</param-value> 19. </init-param> 20. </filter> 21. <filter-mapping> 22. <filter-name>CharacterEncoding</filter-name> 23. <url-pattern>/*</url-pattern> 24. </filter-mapping> 25. 26. 27. 28. <!-- spring 开始--> 29. <!-- 加载spring的过滤器 --> 30. <context-param> 31. <param-name>contextConfigLocation</param-name> 32. <param-value>classpath:spring/spring-*.xml</param-value> 33. </context-param> 34. <listener><!-- 启动web容器时,自动装配spring-dao.xml--> 35. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 36. </listener> 37. <!-- spring 结尾--> 38. 39. 40. <!--配置springmvc的核心过滤器 --> 41. <servlet> 42. <servlet-name>dispatcherServlet</servlet-name> 43. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 44. <init-param> 45. <param-name>contextConfigLocation</param-name> 46. <param-value>classpath:spring/springmvc.xml</param-value> 47. <!-- 容器启动自动加载springmvc.xml --> 48. </init-param> 49. </servlet> 50. <servlet-mapping> 51. <servlet-name>dispatcherServlet</servlet-name> 52. <url-pattern>*.do</url-pattern> 53. </servlet-mapping> 54. 55. </web-app>
spring-mvc.xml 路径: src/main/resources/spring/springmvc.xml
1. <?xml version="1.0" encoding="UTF-8"?> 2. <beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:aop="http://www.springframework.org/schema/aop" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xmlns:mvc="http://www.springframework.org/schema/mvc" 7. xmlns:context="http://www.springframework.org/schema/context" 8. xsi:schemaLocation="http://www.springframework.org/schema/beans 9. http://www.springframework.org/schema/beans/spring-beans.xsd 10. http://www.springframework.org/schema/aop 11. http://www.springframework.org/schema/aop/spring-aop.xsd 12. http://www.springframework.org/schema/context 13. http://www.springframework.org/schema/context/spring-context.xsd 14. http://www.springframework.org/schema/tx 15. http://www.springframework.org/schema/context/spring-tx.xsd 16. http://www.springframework.org/schema/mvc 17. http://www.springframework.org/schema/mvc/spring-mvc.xsd"> 18. 19. <!-- 开启注解扫描 --> 20. <context:component-scan base-package="ypc.zwz.controller"/> 21. 22. <!-- 配置springmvc的驱动,并开启了对JSON数据格式的支持 --> 23. <mvc:annotation-driven/> 24. 25. <!-- 配置视图解析器 --> 26. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 27. <property name="prefix" value="/WEB-INF/views/"/> 28. <property name="suffix" value=".jsp"/> 29. </bean> 30. 31. 32. </beans>
spring-dao.xml 地址: src/main/resources/spring/spring-dao.xml
1. <?xml version="1.0" encoding="UTF-8"?> 2. <beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xsi:schemaLocation="http://www.springframework.org/schema/beans 6. http://www.springframework.org/schema/beans/spring-beans.xsd 7. http://www.springframework.org/schema/context 8. http://www.springframework.org/schema/context/spring-context.xsd"> 9. 10. <!-- 配置注解扫描 --> 11. <context:component-scan base-package="ypc.zwz.service"/> 12. 13. <!-- 加载数据库配置文件 --> 14. <context:property-placeholder location="classpath:resource/jdbc.properties"/> 15. 16. <!-- 数据库连接池 --> 17. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 18. <!-- 配置数据库连接池属性 --> 19. <property name="driverClass" value="${jdbc.driver}"/> 20. <property name="jdbcUrl" value="${jdbc.url}"/> 21. <property name="user" value="${jdbc.username}"/> 22. <property name="password" value="${jdbc.password}"/> 23. 24. <!-- c3p0连接池私有属性 --> 25. <property name="maxPoolSize" value="30"/> 26. <property name="minPoolSize" value="10"/> 27. <!-- 关闭连接后不自动commit --> 28. <property name="autoCommitOnClose" value="false"/> 29. <!-- 获取连接超时时间 --> 30. <property name="checkoutTimeout" value="10000"/> 31. <!-- 当获取连接失败后重新连接的次数 --> 32. <property name="acquireRetryAttempts" value="2" /> 33. </bean> 34. 35. <!-- 配置SqlSessionFactory对象 --> 36. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 37. <!-- 注入数据库连接池 --> 38. <property name="dataSource" ref="dataSource"/> 39. <!-- 启用mybatis的别名配置 --> 40. <property name="typeAliasesPackage" value="ypc.zwz.pojo"/> 41. <!-- 扫描Mapper层的配置文件 --> 42. <property name="mapperLocations" value="classpath:ypc/zwz/mapper/*.xml"/> 43. </bean> 44. 45. <!-- 启用mybatis的接口代理开发模式(接口和Xml配置必须同名,并且在同一目录下) --> 46. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 47. <property name="basePackage" value="ypc.zwz.mapper"/> 48. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 49. </bean> 50. 51. </beans>
ArticleController.java 路径 :src/main/java/cn/ypc/controller/ArticleController.java
1. package ypc.zwz.controller; 2. 3. import ypc.zwz.pojo.Summary; 4. import ypc.zwz.service.ArticleService; 5. 6. import org.springframework.beans.factory.annotation.Autowired; 7. import org.springframework.stereotype.Controller; 8. import org.springframework.ui.Model; 9. import org.springframework.web.bind.annotation.RequestMapping; 10. import org.springframework.web.bind.annotation.RequestParam; 11. 12. import javax.servlet.http.HttpServletRequest; 13. import java.util.HashMap; 14. import java.util.List; 15. import java.util.Map; 16. 17. @Controller 18. @RequestMapping(value = "/summary") 19. public class ArticleController { 20. private ArticleService articleService; 21. @RequestMapping(value = "/test1") 22. public String te(@RequestParam(value = "pageCode", defaultValue = "1", required = false) int pageCode,@RequestParam(value = "pageSize", defaultValue = "3", required = false) int pageSize,HttpServletRequest request,Model model) { 23. Summary summary = articleService.findById(23); 24. String str = summary.getR_content(); 25. model.addAttribute("msg",str); 26. return "login/test"; 27. } 28. }