使用Maven构建 基于SpringMVC+Spring+Mybatis(SSM)高效便捷开发框架

本项目是一个整合 SpringMVC+Spring+MyBatis(SSM) 框架的 Demo提供视频部署教程

拥有高效率便捷开发模式,使开发人员更专注于业务,达到面向业务开发。

项目使用 Maven 构建,便于项目管理,支持 Oracle、MySql 等主流数据库。

前端展示界面采用基于 Boostrap 实现的响应式布局,并集成了一系列的动画效果插件,整体界面简洁、美观大方并可优雅的与后台完成交互操作。

项目封装了一系列常用方法、部署运行简单,便于个人或企业进行高效开发。

项目已提交至Github请前往https://github.com/micyo202/yan-demo查看详情。

一、项目开发环境&工具(Environment&Tools)

  • MacOS Sierra / Windows 7
  • MySql 5.7
  • JDK 1.8
  • CentOS 7
  • IntelliJ IDEA 2017.2.5 / Eclipse 4.6.1
  • Navicat Premium 11.1.12
  • Maven 3.3.9
  • Jetty 9.4.6.v20170531 / Tomcat 9.0

二、Maven配置(pom.xml)

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.yan</groupId>
    <artifactId>yan_demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    
    <name>yan_demo</name>
    <description>基于 SpringMVC+Spring+Mybatis 开发的 Yan Frame Demo.</description>
    
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.framework.version>4.3.11.RELEASE</spring.framework.version>
        <aspectj.version>1.8.10</aspectj.version>
        <shiro.version>1.4.0</shiro.version>
        <jackson.version>2.9.1</jackson.version>
        <logback.version>1.2.3</logback.version>
    </properties>
    
    <dependencies>
        <!-- 添加 junit 依赖包 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version> 
            <scope>test</scope>
        </dependency>
        
        <!-- 添加 commons 依赖包 -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.6</version>
        </dependency>

        <!-- 添加 spring 依赖包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.framework.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- 添加 aspectJ 依赖包 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        
        <!-- 添加 shiro 依赖包 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-quartz</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-ehcache</artifactId>
        <version>${shiro.version}</version>
    </dependency>
        
        <!-- 添加 mybatis 依赖包 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
        
        <!-- 添加 mybatis 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.1</version>
        </dependency>
         
        <!-- 添加 druid 依赖包 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.3</version>
        </dependency>
         
        <!-- 添加 mysql 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>

        <!-- 添加 jackson 依赖包 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        
        <!-- 添加 servlet 依赖包 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        
        <!-- 添加 jstl 依赖包 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        
        <!-- 添加 log 依赖包 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>
        
        <!-- 添加 dom4j 依赖包(用于解析 xml)-->
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

    </dependencies>
    
    <build>
        <plugins>
            <!-- 添加 jetty 插件(命令运行方式:进入工程目录执行:mvn jetty:run 启动服务) -->
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.6.v20170531</version>
                <configuration>
                    <!-- 指定监控的扫描时间间隔,0为关闭jetty自身的热部署 -->
                    <scanIntervalSeconds>0</scanIntervalSeconds>
                    <webAppConfig>
                        <contextPath>/yan_demo</contextPath>
                    </webAppConfig>
                    <httpConnector>
                        <port>8888</port>
                    </httpConnector>
                </configuration>
            </plugin>
            
            <!-- 添加 mybatis-generator 插件(命令运行方式:进入工程目录执行:mvn mybatis-generator:generate 生成代码) -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.5</version>
            </plugin>
            
        </plugins>
    </build>
    
</project>

三、项目结构(Construction)

  • com.yan.common:通用功能模块(包含:用户登录、菜单、后台管理等...)
  • com.yan.core:框架核心模块(包括基础的控制器、过滤器、拦截器、类加载器、注入器、注解、以及框架封装的核心方法部分)
  • com.yan.demo:业务模块(根据实际项目名称换掉demo名称,所有业务模块均在该路径下)
  • com.yan.**.controller:控制器路径,存放自己编写业务处理的控制器(继承BaseController)
  • com.yan.**.mapper:持久层映射接口类路径(mbg生成mybatis对应的Mapper映射接口类)
  • com.yan.**.model:模型类路径(mbg生成的模型以及自定义模型)
  • com.yan.junit:单元测试模块(便于撰写单元测试代码)
  • resources/database:数据库sql文件(数据库表结构的*.sql文件,包含Yan Frame框架所需的基本系统数据表,如:用户表、权限表、菜单表等...)
  • resources/mybatis:mapper映射文件(所有mybatis的sql模板*.xml文件)
  • resources/properties:配置文件(如:系统基本配置、数据库配置、日志配置、MyBatis generator配置)
  • resources/spring:spring的配置文件(命名规范:spring-*.xml)
  • webapp/common:公共路径(前台框架的通用*.jsp头文件,页面仅需引入这里面对应的jsp即可)
  • webapp/resources:静态资源路径(包含了js、css、images、doc、plugins等)
  • webapp/views:视图路径(所有业务功能的*.jsp页面)

四、常用方法(Methods)

方法均在继承于BaseController的类中使用this.metodName;进行调用(其中methodName代表需要调用的方法名称)
方法名 参数 返回值 描述
getSession HttpSession 服务器会话 获取服务器会话 session 对象
setSession session 服务器会话 设置服务器会话 session 对象
getRequest HttpServletRequest 用户请求 获取用户请求 request 对象
setRequest request 用户请求 设置用户请求 request 对象
getResponse HttpServletResponse 服务器响应结果 获取服务器响应结果 response 对象
setResponse response 服务器响应结果 设置服务器响应结果 response 对象
getSessionUser TbSysUser 用户对象 获取登录成功后 session 中的存储的用户信息
getMapper type 生成的 Mapper 接口对象类型 T 泛型,传入参数对象的类型Mapper 获取 mapper 对象
getMapper DelegateMapper 通用 mapper,查看自定义 sqlMap 的代理 mapper 对象 获取 delegateMapper 对象
setDataSource dataSource 数据源名称(必须是spring配置中包含的名称) 动态切换数据源方法,设置数据源名称
clearDataSource 清除数据源,在切换完数据源后,进行清理,将数据源还原为默认数据源
offsetPage offset 起始数量;limit 限制条数 分页查询范围,参数均由 bootstrapTable 分页插件进行传入,无需人工控制,只需调用方法即可
resultPage list 查询到的分页结果,为 Page 对象 PageModel<T> 自定义的分页模型,T 为查询的对象 分页结果集对象
resultMsg status 状态值(可根据需求任意设置,无强制标准);msg 消息内容;res 返回的对象 MsgModel 自定义消息模型 消息返回对象
fileUpLoad request 上传方法中传递的 request 对象,并非父类中的 request 对象 List<String> 上传文件成功后的新文件名称,以集合形式返回 文件上传方法,支持多个文件上传
fileDownLoad fileName 需要下载的文件名称 ResponseEntity<byte[]> 下载的文件,在浏览器会进行下载 文件下载方法
isNull obj 需要进行判断的对象 boolean 为null或空返回 true,否则返回 false 判断对象是否为null,或空
obj2Str obj 需要转换的对象 String 对象的值(为null则返回"") 对象转换为 String,通常用于获取 Map 集合中的对象时使用
getUUID String 32位主键字符串 生成 uuid 主键,长度为32位,且为大写模式
base64Encoder str 需要进行编码的字符串 String 进行编码后的结果字符串 对字符串进行 base64 编码
base64Decoder str 已进行 base64 编码的编码字符串 String 解码后的原字符串 对字符串进行 base64 解码
md5 str 需要进行 md5 加密的字符串 String 加密后的结果 对字符串进行 md5 加密算法
currentDate pattern 获取系统时间的格式,如:yyyy-MM-dd HH:mm:ss String 返回格式化后的当前时间 获取系统当前时间
timeStamp2Date timestamp 需要进行转换的时间戳;pattern 转换后的格式 String 格式化后的日期 时间戳转换成日期
date2TimeStamp dateStr 需要进行转换的日期字符串;pattern 日期的格式 String 转换后的时间戳 日期转换为时间戳
readFromFile filePath 文件路径(绝对路径) String 读取的文件内容 从指定文件中读取文件内容
writeToFile content 需要写入文件中的内容 filePath 文件路径(绝对路径) 将内容写入到指定文件中(写入会覆盖文件原有内容,建议先读取,再写入,将读取的内容与需要写入的内容并在一起进行写入)
generatePath path 文件夹路径(绝对路径) 生成指定路径文件夹,先进行判断文件夹是否存在,若不存在则创建对应目录的文件夹,若存在则不进行任何操作
generateFile path 文件路径(绝对路径) 生成指定路径的文件,先进行判断文件是否存在,若不存在则进行创建文件,若存在则不进行任何操作
propertiesValue key 资源文件中的 key 值 String 读取到的 key 对应的 value 值 读取 properties 文件中的值,读取 classpath 下 /properties/config.properties 配置文件
propertiesValue resource 资源文件路径(对应 classpath 中的路径);key 资源文件中的 key 值 String 读取到的 key 对应的 value 值 读取指定路径 properties 文件中的值,会从 classpath 路径下进行查找资源文件

五、示例代码(Codes)

创建一个继承与BaseController的控制器
@Controller
public class XxxController extends BaseController {
    ...
}
获取日志日志记录Logger对象
// 使用注解获取
@LogInject
private static Logger log;

// 使用工厂方法获取
private static Logger log = LoggerFactory.getLogger(XxxController.class);
获取mapper对象
// 注解方式获取delegateMapper
@MapperInject
private DelegateMapper delegateMapper;
// 注解方式获取对象对应的mapper
@MapperInject(XxxMapper.class)
private XxxMapper mapper;

// 获取delegateMapper
this.getMapper();
// 获取对象对应的mapper
this.getMapper(XxxMapper.class);
动态切换数据源
// 注解切换数据源,默认切换扩展数据源
@DynamicDataSource
public String init(){
    ...
}

// 注解切换数据源,传入ENUM类型的数据源名称
@DynamicDataSource(DataSourceName.EXTEND)
public String init(){
    ...
}

// 调用父类方法执行切换数据源(参数名称建议使用框架中已经定义好的,DataSourceName.DEFAULT/EXTEND.getName())
this.setDataSource("extendDataSource");
    ...
this.clearDataSource();
分页查询后台代码
@RequestMapping("/list")
@ResponseBody
public PageModel<Xxx> list(int offset, int limit) {
    // 调用父类方法传入分页参数
    this.offsetPage(offset, limit);
    List<Xxx> list = mapper.selectByExample(null); // 调用查询方法
    return this.resultPage(list);
}
分页查询前台代码
<table id="table"><table>

$('#table').bsTable({
        url: '${pageContext.request.contextPath}/xxx/list',
        idField: 'id',
        columns: [
            {field: 'state', checkbox: true},
            {field: 'id', title: 'id', align: 'center'},
            ...
            ]
    });
文件上传
@RequestMapping("/upload")
public String upload(HttpServletRequest request) {
    // 调用父类的上传方法,在jsp中必须指定form为enctype="multipart/form-data"
    List<String> fileNames = this.fileUpLoad(request);
    return "success";
}
文件下载(在jsp页面使用通用的下载方法,使用restful风格)
<a href="${pageContext.request.contextPath}/文件名称/download">文件下载</a>
自定义文件下载后台方法
@RequestMapping("/download")
public ResponseEntity<byte[]> download(String fileName) {
    // 调用父类文件下载方法
    return this.fileDownLoad(fileName);
}
常用DelegateMapper及对象Mapper方法
// 使用自定义sql模板查询单个对象
Demo demo = delegateMapper.selectOne(statement);
Demo demo = delegateMapper.selectOne(statement, parameter);
        
// 使用自定义sql模板查询对象集合
List<Demo> list = delegateMapper.selectList(statement);
List<Demo> list = delegateMapper.selectList(statement, parameter);

// 使用自定义sql模板有范围的查询,(每次返回指定的对象条数集合)
List<Demo> list = delegateMapper.selectList(statement, parameter, rowBounds);

// 使用自定义sql模板进行分页查询
PageModel<Demo> page = delegateMapper.selectPagination(statement, offset, limit);
PageModel<Demo> page = delegateMapper.selectPagination(statement, parameter, offset, limit);

// 使用自定义sql模板保存
int res = delegateMapper.insert(statement);
int res = delegateMapper.insert(statement, parameter);

// 使用自定义sql模板修改
int res = delegateMapper.update(statement);
int res = delegateMapper.update(statement, parameter);

// 使用自定义sql模板删除
int res = delegateMapper.delete(statement);
int res = delegateMapper.delete(statement, parameter);

// 使用对象方法根据主键查询
Demo demo = mapper.selectByPrimaryKey(id);

// 使用对象方法根据criteria查询
List<Demo> list = mapper.selectByExample(example);

// 使用对象方法根据criteria分页查询
this.offsetPage(offset, limit);
List<Demo> list = mapper.selectByExample(example);
this.resultPage(list); // 返回的结果集

// 使用对象方法添加
int res = mapper.insert(record);
int res = mapper.insertSelective(record);

// 使用对象方法根据主键修改
int res = mapper.updateByPrimaryKey(record);
int res = mapper.updateByPrimaryKeySelective(record);

// 使用对象方法根据criteria修改
int res = mapper.updateByExample(record, example);
int res = mapper.updateByExampleSelective(record, example);

// 使用对象方法根据主键删除
int res = mapper.deleteByPrimaryKey(productCode);

// 使用对象方法删除根据criteria删除
int res = mapper.deleteByExample(example);

更多方法使用请参考项目中API文档或demo模块下的代码

六、效果预览(Preview)

login

web

mobile

七、许可证(License)

MIT License

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,283评论 0 4
  • Spring 技术笔记Day 1 预热知识一、 基本术语Blob类型,二进制对象Object Graph:对象图...
    OchardBird阅读 929评论 0 2
  • SSM框架整合理解 把IntelliJ IDEA+Maven+Spring + SpringMVC + MyBat...
    青年马土豆阅读 9,030评论 0 21
  • 公司的手写板,让我测试下怎么样,我临摹了自己画过的蝴蝶,只是改了颜色,画完了,领导问怎么样,我说挺好用的,还是这个...
    辣妈赵十八阅读 476评论 8 4
  • 有一群这样的人,假惺惺,披着羊皮的狼,觉得自己很聪明却不知自己的所作所为被别人看的很透,只不过不揭穿而已,这个社会...
    在路上的少年阅读 368评论 0 0