久没有写博客了, 今年事情太多了, 也没了心思. 去深圳出差, 更重要的结婚的事情, 一茬接一茬. 好在最近闲暇一些, 就想记录一些曾经困扰过我的问题(现在用spring boot真是太方便了, 很多问题, 都不会再是问题).
SSM(spring + springmvc + mybatis), 是一款非常流行的框架. 所以把这款框架搭建起来, 也是开发的一项基本功.
SSM的整合, 分为两部分:
一部分是 spring与springmvc间的整合,
一部分是 spring与mybatis间的整合.
其实, 也应该是这样, 因为 springmvc与mybatis间, 没有任何关系. 都只是与spring有关系.
初步的目录结构:
不管是用eclipse还是用idea, 都是使用maven来管理jar包, 且把引用放在pom.xml文件中, 可以告别繁琐的jar包引入.
ssh, ssm 框架的 pom.xml文件, 网上都是能搜得到的, 大把大把, 真的要去搭框架的时候, 可以去网上直接下一个就行了. 没必要这么麻烦.
一. jar包引入
<properties> <spring.version>4.3.5.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- spring核心包 --> <dependency> <groupId>org.springframework</groupId> <!--包含Spring 框架基本的核心工具类--> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <!--所有应用都用到,包含访问配置文件,创建和管理bean等,是Spring IOC的基础实现--> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <!--提供在基础IOC功能上的扩展服务--> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <!--Spring提供的对AspectJ框架的整合--> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <!--Spring的面向切面编程,提供AOP(面向切面编程)的实现--> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <!-- springmvc相关的spring包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!--spring数据库相关包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <!--对象的XML映射,可以让Java与XML之间来回切换--> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <!--用于在Spring 中集成AspectJ AspectJ LTW织入器--> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.10</version> </dependency> <!-- mybatis/spring包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!-- mysql数据库链接包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!-- 日志包 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.20</version> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.18</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.11</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.5</version> </dependency> <!--jackson包是springmvc返回json数据时用到的--> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>1.9.13</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.5.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.5.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.13</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> </dependencies> <build> <finalName>ssm</finalName> <plugins> <!--解决idea中java compile 和 language level在更新pom文件后,重置到5的版本--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
上面的包, 还包含了mybatis的包, 到整合mybatis的时候, 就不会再写一遍pom.xml文件了
二. web.xml文件配置spring和springmvc入口
<!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> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:conf/application.xml</param-value> </context-param> <!-- 加载log4j的配置文件log4j.properties --> <!--<context-param> <param-name>log4jConfigLocation</param-name> <param-value> classpath:conf/log4j.properties </param-value> </context-param>--> <!-- 设定刷新日志配置文件的时间间隔,这里设置为10s --> <!-- <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>10000</param-value> </context-param>--> <!--解决post乱码问题--> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置spring启动listener入口 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener>--> <!--springmvc入口servlet--> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--contextConfigLocation如果不配置, 则会按照默认的方式去找文件, 如果找不到, 则会抛出异常, 所以这里推荐还是要写一下. 我这里配置的空, 因为在前面application.xml中, 已经import了这里需要的xml文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value> <!--classpath:conf/spring-mvc.xml--> </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <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> </web-app>
在application.xml文件中, 我引入了spring-mvc.xml文件, 这样 在web.xml 文件中, 配置 DispatcherServlet 的时候, 就可以将xml文件路径配置为空. 否则, 程序会按照特定的规则去查找xml文件. 如果找不到, 则会抛出异常.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" default-lazy-init="true"> <!-- 自动搜索bean --> <context:annotation-config /> <!-- 开启注解 --> <mvc:annotation-driven/> <context:component-scan base-package="org.elvin.ssm" /> <import resource="classpath:conf/spring-mvc.xml" />
<!--在进行mybatis的整合的时候, 这句话要注释回去--> <!--<import resource="classpath:conf/spring-mybatis.xml"/>--> </beans>
三. springmvc配置文件: spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" 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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- 注解扫描包 --> <context:component-scan base-package="org.elvin.ssm.controller" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan> <!-- 开启注解 --> <!--<mvc:annotation-driven/>--> <!--静态资源访问--> <mvc:default-servlet-handler /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp" /> </bean> <!-- 避免IE在ajax请求时,返回json出现下载 --> <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> </list> </property> </bean> </beans>
配置文件就暂时到这里了, 接下来看一下java代码
四. java代码
在controller文件夹下, 加入一个控制器: HelloController.java
package org.elvin.ssm.controller; import org.elvin.ssm.pojo.*; import org.elvin.ssm.utils.CollectionUtilsLocal; import org.joda.time.DateTime; import org.springframework.stereotype.Controller; import org.springframework.ui.*; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.*; /** * author: Elvin * datetime: 2017/11/29 20:06 * description: */ @Controller @RequestMapping("hello") public class HelloController { @GetMapping("index") public String index(ModelMap model){ List<Book> bookList = getBookList(); model.put("bookList",bookList); return "index"; } @RequestMapping(value = "book", method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public Book book(@RequestParam("id") Integer id){ List<Book> bookList = getBookList(); Book b = CollectionUtilsLocal.findOneBy(bookList, n -> n.getId().equals(id)); return b; } //region private method private List<Book> getBookList(){ List<Book> bookList = new ArrayList<>(); String[] nameStrs = {"吴", "一", "雪", "动", "额", "阿", "前", "里", "排"}; Random r = new Random(); String timeStr = new DateTime().toString("yyyy-MM-dd HH:mm:ss"); for (int i = 0; i < 10 ; i++){ Book b = new Book(); b.setId(i+1); b.setName(nameStrs[r.nextInt(5)] + nameStrs[r.nextInt(9)]); b.setPublishTime(timeStr); b.setPrice(r.nextInt(100)); bookList.add(b); } return bookList; } //endregion }
这里有个帮助类, 顺手也贴出来, 期望达到的目的就是, 拷贝下来, 就能直接跑起来, 不需要调试
CollectionUtilsLocal.java
package org.elvin.ssm.utils; import java.util.*; import java.util.function.Predicate; /** * author: Elvin * Date: 2017/11/30 9:33 * Description: */ public class CollectionUtilsLocal { /** * 功能描述:list去重 **/ public static void removeDuplicateWithOrder(List list) { Set set = new HashSet(); List newList = new ArrayList(); for (Iterator iter = list.iterator(); iter.hasNext(); ) { Object element = iter.next(); if (set.add(element)){ newList.add(element); } } list.clear(); list.addAll(newList); } /** * 判断list是否为空,包括对象为null,内容为空 * * @param list * @return true 代表不为空,false代表为空*/ @SuppressWarnings("rawtypes") public static boolean isNotNullList(List list) { if (null != list && (!list.isEmpty())) { return true; } return false; } /** * 判断集合是否是null或者空集合 * @param list * @return */ public static boolean isNullOrEmptyList(List list){ if(list == null || list.isEmpty()){ return true; } return false; } /** * @param map * @return true 代表不为空,false代表为空 * @Title: isNotNullMap * @Description: 校验map是否为空 * @Since: 2017年6月12日下午1:15:31 */ @SuppressWarnings("rawtypes") public static boolean isNotNullMap(Map map) { if (null != map && !map.isEmpty()) { return true; } return false; } /** * 根据条件删除集合中的元素 * @param list 待删除元素的集合 * @param predicate 条件 * @param <T> * @return */ public static <T> List<T> removeAll(List<T> list, Predicate<T> predicate){ if (!isNotNullList(list)) { return null; } List<T> resList = new ArrayList<>(); for (T item : list) { if (!predicate.test(item)) { resList.add(item); } } return resList; } /** * 根据查询条件查找满足条件的数据,并返回 * * @param list 要查找的集合 * @param predicate 查找的条件 * @param <T> * @return */ public static <T> T findOneBy(List<T> list, Predicate<T> predicate) { if (!isNotNullList(list)) { return null; } for (T item : list) { if (predicate.test(item)) { return item; } } return null; } /** * 根据条件查找集合中所有的数据 * @param list 待查找集合 * @param predicate 条件 * @param <T> * @return */ public static <T> List<T> findAllBy(List<T> list, Predicate<T> predicate) { if (!isNotNullList(list)) { return null; } List<T> resList = new ArrayList<>(); for (T item : list) { if (predicate.test(item)) { resList.add(item); } } return resList; } }
在pojo文件夹下, 加入一个实体文件: Book.java
package org.elvin.ssm.pojo; /** * author: Elvin * datetime: 2017/11/29 20:46 * description: */ public class Book { private Integer id; private String name; private Integer price; private String publishTime; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } public String getPublishTime() { return publishTime; } public void setPublishTime(String publishTime) { this.publishTime = publishTime; } }
五. 前台代码
在jsp文件夹下加入一个index.jsp文件
<%-- Created by IntelliJ IDEA. User: Elvin Date: 2017/11/30 Time: 9:17 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> </head> <body> <h1>ssm</h1> <table> <thead> <tr> <td>id</td> <td>name</td> <td>price</td> <td>publishTime</td> </tr> </thead> <tbody> <c:if test="${bookList!=null && bookList.size()>0}"> <c:forEach var="item" items="${bookList}"> <tr> <td>${item.id}</td> <td>${item.name}</td> <td>${item.price}</td> <td>${item.publishTime}</td> </tr> </c:forEach> </c:if> </tbody> </table> </body> </html>
六. 结果展示
1. 访问页面:
2. 访问数据
如果想让springmvc直接返回数据, 要注意几点
1. 要引入 jackson 的jar包, springmvc没有提object to json 的功能
2. 在springmvc的配置文件中, 要加上 <mvc:annotation-driven/>
3. 在controller控制器的action方法上面加上 @ResponseBody 注解
3. 访问静态资源
想要访问静态资源, 需要加上 <mvc:default-servlet-handler /> , 或者自己配置一些资源, 否则是不能访问到的.