本项目案例使用eclipse企业版,整合Spring、Springmvc、Mybatis框架(SSM框架),在反复测试配置和测试并确保正确无误的基础上,围绕以下案例介绍:
前端发出请求给后端,后端获取MySQL数据库中的数据,然后以JSON格式返回到前端,前端再对这些数据进行组织并显示出来
1.前端通过Ajax发送请求参数到后端,首先访问web.xml文件也就访问了spring-mybatis.xml、spring-mvc.xml文件,这两个xml文件正是配置SSM框架的控制核心
2.spring-mybatis.xml配置MySQL数据连接参数,配置需要扫描的Service层的包、Dao层的包,在该文件中指向了另一个mapper-config.xml文件用于扫描Dao层具体的接口
3.spring-mvc.xml配置了要扫描的Controller包,还可用于配置Controller层方法返回的视图特性
4.由配置文件去Controller层找对应的处理方法,找到后并将参数注入到相应的方法中
5.进入Controller层的方法内部后,根据需要则去调用Service层或直接Dao层方法以实现对数据库的访问
6.Service层或Dao层处理完毕将结果返回,返回JSON类型数据则需要进行类型转换
7.前端页面将返回的JSON数据进行组织并显示出来
主要依赖
1. mysql-connector-java-5.1.10-bin.jar
2. spring-5.2.3
3. mybatis-3.5.4.jar
4. mybatis-spring-2.0.5.jar
5. gson-2.8.5.jar
目录结构
依赖导入
1. Dao层
2. Service层
3. Controller层
4. 配置mapper-config.xml
5. 配置文件:spring-mybatis.xml
6. 配置文件:spring-mvc.xml
7. com.test.QueryTest类单独测试配置
8. 实现跨域请求的过滤器
9. 配置文件:web.xml
10. 前端请求页面:index.html
1. Dao层
com.dao.TestDao是一个接口,这里实现的是注解sql语句,也可以使用非注解方式,而非注解需要单独在一个xml中配置查询语句
package com.dao; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Select; /** * Dao层: * 1.确保 mybatis-spring包正确导入到环境依赖中 * 2.必须要在配置文件中配置dao层的扫描路径 (spring-mybatis.xml): * <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> * <!-- 扫描包路径,如果需要扫描多个包,中间使用半角逗号隔开 --> * <property name="basePackage" value="com.dao" /> * </bean> * 3.这里使用 Map作为参数,则 Map 的key必须与 注解上的查询语句 "#{ }" 中的名字一致,个数一致 **/ public interface TestDao { @Select("select * from tb_test where sex=#{sex} and height>#{height} limit 0,10") public List<Map<String,Object>> queryInfo(Map<String,Object> mp); }2. Service层
com.serv.TestService用于协助Controller层处理,但该类不是必须的,详情看注释
package com.serv; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.dao.TestDao; import com.google.gson.Gson; import com.google.gson.GsonBuilder; /** * @author wonzeng * 2020年7月3日 * Service层使用规则总结: * 1. 用于协助Controller层处理业务逻辑 * 2. 其存在不是必须的,处理较简单时可以直接合并Controller层 * 3. 如果使用了Service层,Service类上必须要注解 @Service ,类似的也可用 @Component @Repository 等 * 4. 必须在配置文件 (spring-mybatis.xml)中做如下配置,才能使注解被扫描到: * <context:component-scan base-package="com.service"></context:component-scan> * */ @Service public class TestService { /** * 该注解同样可以直接配置到 Controller层 * 直接在Controller层通过注解对象testDao调用Dao层方法 */ @Autowired TestDao testDao; public String queryService(Map<String,Object> mp) { // TODO Auto-generated constructor stub List<Map<String,Object>> ob = testDao.queryInfo(mp); //转换日期格式,也可用:new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); return gson.toJson(ob); } }3. Controller层
com.serv.TestService 是处理的业务处理的核心,前端请求由此进入处理
package com.cont; import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import com.serv.TestService; /** * @author wonzeng * 2020年7月3日 * Controller层: * 1.必须配置spring-mvc.xml文件 * 2.尤其是以下扫描路径必须正确配置 * <context:component-scan base-package="com.cont" /> * <bean * class="org.springframework.web.servlet.view.InternalResourceViewResolver"> * <property name="prefix" value="/" /> * <property name="suffix" value=".html" /> * </bean> * */ @Controller public class ControllerTest { @Autowired TestService testService; // @Autowired // HttpServletRequest request; @Autowired HttpServletResponse response; public ControllerTest() { // TODO Auto-generated constructor stub } /** * @param mp * @ResponseBody 注解通常使用在控制层 controller的方法上 * 1. 其作用是将方法的返回值以特定的格式写入到response的body区域, 进而将数据返回给客户端 * 2. 当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象 * 3. 一种是可直接调用 response.getWriter()将String送到前端,另一种还可使用return返回String * 4. 若返回String,默认按iso8859-1编码,页面可能出现乱码 * 此时可以将 @RequestMapping("/queryinfo.do") 修改为: * @RequestMapping(value="/queryinfo.do",produces="text/html;charset=utf-8") */ @ResponseBody @RequestMapping(value="/queryinfo.do",produces="text/html;charset=utf-8") public String queryTest(@RequestParam Map<String,Object> mp) { mp.forEach((k,v)->{ System.out.println("ControllerTest.queryTest():"+k+"\t"+v); }); String res = testService.queryService(mp); System.out.println("json:"+res); // 返回类型为void,则可以直接使用如下: // try { // response.getWriter().print(res); // } catch (IOException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } return res; } }4. 配置mapper-config.xml
<?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> <!-- 数据库连接使用spring管理,此处则无需进行数据库连接 --> <!-- <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> 配置数据库连接信息 <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="666666"/> </dataSource> </environment> </environments> --> <mappers> <!-- 使用注解方式 --> <mapper class="com.dao.TestDao"/> <!-- 不使用注解,用以下方式--> <!-- <mapper resource="com/UserMapper.xm"/> --> </mappers> </configuration>5. 配置文件:spring-mybatis.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans https://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/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 </value> </property> <property name="username"> <value>root</value> </property> <property name="password"> <value>666666</value> </property> </bean> <!--扫描Service里面的注解,为service注入提供来源 --> <context:component-scan base-package="com.serv"></context:component-scan> <!-- SqlSessionFactory配置 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!--如果使用注解方式,建议使用以下方法--> <property name="configLocation" value="classpath:mapper-config.xml"/> <!-- 加载mybatis的全局配置文件,不使用注解常用以下方式 --> <!-- 加载单个配置文件: <property name="mapperLocations" value="classpath:userMapper.xml" /> --> <!-- 加载多个配置文件 ,使用通配符可能会加载相冲突的xml文件,最好使用list列出 --> <!-- <property name="mapperLocations"> <list> <value>classpath:userMapper.xml</value> </list> </property> --> </bean> <!-- mapper扫描器,扫描dao --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 扫描包路径,如果需要扫描多个包,中间使用半角逗号隔开 --> <property name="basePackage" value="com.dao" /> </bean> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>6. 配置文件:spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- spring-mvc --> <mvc:annotation-driven /> <context:component-scan base-package="com.cont" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/" /> <property name="suffix" value=".html" /> </bean> </beans>7. com.test.QueryTest类单独测试配置
package com.test; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.dao.TestDao; import com.serv.TestService; public class QueryTest { public QueryTest() { // TODO Auto-generated constructor stub } public static void main(String[] args) { BeanFactory context=new ClassPathXmlApplicationContext("spring-mybatis.xml"); TestService testService = context.getBean(TestService.class); Map<String,Object> mp = new HashMap<String,Object>(); mp.put("sex", "男"); mp.put("height", 150); String p = testService.queryService(mp); System.out.println("第一种:通过service层调用查询(json字符串):"); System.out.println(p); TestDao testDao = context.getBean(TestDao.class); List<Map<String,Object>> arr = testDao.queryInfo(mp); System.out.println("\n第二种:通过dao层调用查询:"); arr.forEach((m)->{ m.forEach((k,v)->{ System.out.print(v+"\t"); }); System.out.println(); }); } }测试截图
8. 实现跨域请求的过滤器
package com.cors; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author wonzeng * 2020年7月3日 * 跨域请求的过滤器, 需要在web.xml中配置filter标签 */ public class MyCorsFilter implements Filter { public MyCorsFilter() { // TODO Auto-generated constructor stub } /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here /* 允许跨域的主机地址 */ HttpServletResponse response = (HttpServletResponse)servletResponse; HttpServletRequest request = (HttpServletRequest) servletRequest; // response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); // response.setHeader("Access-Control-Allow-Headers","*"); response.setHeader("Access-Control-Allow-Method","*"); response.setHeader("Access-Control-Expose-Headers", "*"); // 允许所有的域名跨域访问 // response.setHeader("Access-Control-Allow-Origin","*"); response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); response.setHeader("Access-Control-Allow-Credentials", "true"); // pass the request along the filter chain chain.doFilter(servletRequest, servletResponse); } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } }9. 配置文件:web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0"> <display-name>Spring5</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 跨域请求 xml配置 --> <filter> <filter-name>CorsFilter</filter-name> <filter-class>com.cors.MyCorsFilter</filter-class> </filter> <filter-mapping> <filter-name>CorsFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--此处如果不指定context-param及param-value,则在servlet的param-value中只能使用/WEB-INF/applicationContext.xml--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mybatis.xml</param-value> </context-param> <servlet> <servlet-name>dispatcher</servlet-name> <!-- 请求触发器 --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!--param-value可缺省--> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup><!-- 提前启动 --> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.do</url-pattern> <!-- 或*.action --> </servlet-mapping> <!-- 解决springMVC的post乱码 --> <filter> <filter-name>springUtf8Encoding</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> <filter-mapping> <filter-name>springUtf8Encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>10. 前端请求页面:index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <style> /* 奇偶选择器 */ table.contab tr:nth-of-type(odd){background-color: #c3dde0;} table.contab tr:nth-of-type(even){background-color: #d4e3e5;} table.contab { font-family: verdana,arial,sans-serif; font-size:11px; color:#333333; border-width: 1px; border-color: #a9c6c9; border-collapse: collapse; } table.contab th { border-width: 1px; padding: 5px; border-style: solid; border-color: #a9c6c9; } table.contab td { border-width: 1px; padding: 4px; border-style: solid; border-color: #a9c6c9; } </style> <script> function query() { var url = "http://localhost:8080/SpringMybatis/queryinfo.do"; var req = new XMLHttpRequest(); req.open("POST", url, true); req.withCredentials = true; req.setRequestHeader("Content-type", "application/x-www-form-urlencoded;charset=UTF-8"); req.onerror = function() { alert("请求错误"); }; req.onreadystatechange = function() { if (req.readyState == 4 && req.status == 200) { callBack(req.responseText); } }; var params = document.getElementsByName("param"); var ps = "sex="+params[0].value+"&height="+params[1].value; req.send(ps); } function callBack(param){ var arr = JSON.parse(param); var res = ""; if(arr.length==0){ document.getElementById("content").innerHTML ="查询结果为空"; return; } res = "<table class=\"contab\" style=\"width:600px;\">"; res +="<tr>"; var heads = []; for(var k in arr[0]){ heads.push(k); res+="<th>"+k+"</th>"; } res +="</tr>"; for(var i=0;i<arr.length;i++){ var item = arr[i]; res +="<tr>"; for(var j=0;j<heads.length;j++){ res+="<td>"+item[heads[j]]+"</td>"; } res +="</tr>"; } res +="</table>"; document.getElementById("content").innerHTML = res; } window.onload=function(){ query(); } </script> </head> <body> <h2>查询选项</h2> <p> 性别:<select name="param"> <option value="女" selected="selected">女</option> <option value="男">男</option> </select> 最低身高:<input type="number" name="param" value="150"> <input type="button" onclick="query()" value="查询"> </p> <h2>显示数据</h2> <div id="content"></div> </body> </html>案例源码