
本项目是一个基于 SpringMVC+Spring+MyBatis(SSM) 支持分布式的高效率便捷开发框架,使开发人员更专注于业务,达到面向业务开发。
项目使用 Maven 构建,便于项目管理,可支持 Oracle、MySql 等主流数据库。
项目模块化分层明确,便于后期维护等工作。
前端展示界面采用基于 Boostrap 实现的响应式布局,并集成了一系列的动画效果插件,整体界面简洁、美观大方并可优雅的与后台完成交互操作。
项目目标是为中小型企业打造全方位的J2EE企业级开发解决方案,提高工作效率。
该项目是yan-demo单节点项目的升级版,支持分布式,持续更新中,敬请期待...。
- beta 0.1.0:模块优化,删除不必要的模块,优化代码(模块详情参考:三、项目结构)
- beta 0.0.5:前端添加ECharts,便于图形化展示
- beta 0.0.4:添加JMS(ActiveMQ)消息服务(目前仅测试方法,暂无业务流转,后期逐渐完善细化)
- beta 0.0.3:添加Solr搜索引擎服务(基本的全文检索功能,可根据实际需求情况进行二次开发,后期本人再逐渐完善)
- beta 0.0.2:优化整体代码、添加更多注释,结构更清晰、代码更易懂
- beta 0.0.1:将原有yan-demo项目重构,保留原有功能,模块拆分、优化项目结构
- 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.1
yan -- 根目录
├── yan-api -- 接口模块(提供核心接口方法)
| ├── main -- 主模块路径
| | ├── java -- java类路径
| | | ├── com.yan.api -- 核心接口包
| | | | ├── jms -- 消息服务接口
| | | | ├── persistence -- 持久化接口
| | ├── resources -- 资源配置路径
├── yan-common -- 公共模块
| ├── main -- 主模块路径
| | ├── java -- java类路径
| | | ├── com.yan.common -- 公共类包
| | | | ├── constant -- 常亮定义类
| | | | ├── model -- 通用模型
| | | | ├── support -- 支持类
| | ├── resources -- 资源配置路径
├── yan-core -- 核心模块(提供核心方法)
| ├── main -- 主模块路径
| | ├── java -- java类路径
| | | ├── com.yan.core -- 核心类包
| | | | ├── annotation -- 注解类
| | | | ├── aspect -- 切面类
| | | | ├── controller -- 控制器
| | | | ├── injector -- 注入类
| | | | ├── listener -- 消息消费者监听器
| | | | ├── shiro -- 安全认证类
| | | | ├── spring -- spring扩展类
| | ├── resources -- 资源配置路径
├── yan-dao -- 数据库访问模块(该模块主要通过 mbg 插件生成相应的模型及接口映射)
| ├── main -- 主模块路径
| | ├── java -- java类路径
| | | ├── com.yan.dao -- dao层包
| | | | ├── mapper -- 接口映射类
| | | | ├── model -- 数据库模型类
| | ├── resources -- 资源配置路径
| | | ├── mybatis -- sqlMap映射文件
| | | ├── properties -- 配置文件
├── yan-service -- 服务模块(核心接口方法实现)
| ├── main -- 主模块路径
| | ├── java -- java类路径
| | | ├── com.yan.service -- 服务包
| | | | ├── jms -- 消息服务接口实现类
| | | | ├── persistence -- 持久化接口实现类
| | ├── resources -- 资源配置路径
├── yan-test -- 测试模块(用于撰写测试代码,与项目整体无关)
| ├── main -- 主模块路径
| | ├── java -- java类路径
| | | ├── com.yan.test -- 测试包
| | ├── resources -- 资源配置路径
| ├── test -- 单元测试路径
├── yan-web -- web模块
| ├── main -- 主模块路径
| | ├── java -- java类路径
| | | ├── com.yan.controller -- 业务处理控制器包
| | ├── resources -- 资源配置路径
| | | ├── database -- 数据库sql文件
| | | ├── properties -- 项目配置文件
| | | ├── spring -- spring的配置文件
| | ├── webapp -- web应用根路径
| | | ├── common -- 公共路径
| | | ├── resources -- 静态资源路径
| | | ├── views -- 视图路径
- 下载项目,并且导入到IDE开发工具中(建议使用:IntelliJ IDEA)
- 使用 Maven 构建项目
- 创建数据库并执行 yan-web 中 resources/database 路径下的 .sql 文件,创建整个项目必要的表(如:用户表、资源表、日志记录表等...)
- 修改 yan-web 中 resources/properties 路径下的 .properties 配置文件(具体修改方法,详见 - 五、配置说明)
- 完成以上步骤就可以正常部署启动服务了(使用 jetty / tomcat 均可)[详细部署过程在这里就不多做阐述了],接下来进入开发阶段
- 根据实际业务需求,在对应的数据库中创建业务表,表命名规范:“模块名_表名” 如:SYS_RESOURCE(系统模块资源表)
- 修改 yan-web 中 resources 路径下的 generatorConfig.xml 中的 targetPackage 包名及 tableName 表名,使用 MyBatis generator 插件生成对应的持久层模块代码(Maven 执行命令:mvn mybatis-generator:generate),具体配置请参考MyBatis GeneratorXML Configuration,注:请将所有业务对象模型 Model 生成在 yan-model 模块下,所有 mapper接口 及 sql映射xml 生成在 yan-api 模块下
- 在 yan-web 模块中 src/main/java 路径下创建对应的 controller 控制器,该控制器类命名规范以 Controller 结尾,并继承于 BaseController 类,所有的业务操作基本都是在这里完成
- 编写控制器业务处理代码,具体使用参考 - 七、示例代码
- 在 yan-web 模块中 src/main/webapp/views 路径下创建对应的jsp页面,并编写前端页面展示代码
名称(Key值) |
描述 |
setting.upload |
文件上传路径(绝对路径) |
- |
- |
logback.name |
日志前缀名称(一般使用项目名称,便于区分) |
logback.path |
日志存放路径(绝对路径) |
- |
- |
solr.builder |
Solr搜索引擎服务地址 |
- |
- |
amq.brokerURL |
activeMQ服务地址 |
amq.userName |
activeMQ管理端用户名 |
amq.password |
activeMQ管理端密码 |
- |
- |
mbg.jar |
mgb插件链接数据库所需的jar包(绝对路径) |
mbg.path |
生成代码的路径(绝对路径) |
- |
- |
default.db.username |
默认数据库用户名 |
default.db.password |
默认数据库密码 |
default.db.driverClassName |
默认数据库驱动类 |
default.db.url |
默认数据库链接地址 |
- |
- |
dextend.db.username |
扩展数据库用户名(用于多数据源切换) |
dextend.db.password |
扩展数据库密码(用于多数据源切换) |
dextend.db.driverClassName |
扩展数据库驱动类(用于多数据源切换) |
dextend.db.url |
扩展数据库链接地址(用于多数据源切换) |
- |
- |
db.initialSize |
初始化时建立物理连接的个数 |
db.minIdle |
最小连接池数量 |
db.maxActive |
最大连接池数量 |
db.maxWait |
获取连接时最大等待时间,单位毫秒 |
db.timeBetweenEvictionRunsMillis |
配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 |
db.minEvictableIdleTimeMillis |
配置一个连接在池中最小生存的时间,单位是毫秒 |
db.validationQuery |
用来检测连接是否有效的sql |
db.testWhileIdle |
建议配置为true,不影响性能,并且保证安全性 |
db.testOnBorrow |
申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
db.testOnReturn |
归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
db.poolPreparedStatements |
是否缓存preparedStatement,也就是PSCache |
db.maxPoolPreparedStatementPerConnectionSize |
每个连接上PSCache的大小 |
db.filters |
属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall |
方法名 |
参数 |
返回值 |
描述 |
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 为查询的对象 |
分页结果集对象 |
resultMsg |
status 状态值(可根据需求任意设置,无强制标准);msg 消息内容;res 返回的对象 |
MsgModel 自定义消息模型 |
消息返回对象 |
fileUpLoad |
request 上传方法中传递的 request 对象,并非父类中的 request 对象 |
List 上传文件成功后的新文件名称,以集合形式返回 |
文件上传方法,支持多个文件上传 |
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 路径下进行查找资源文件 |
@Controller
public class XxxController extends BaseController {
...
}
// 使用注解获取
@LogInject
private static Logger log;
// 使用工厂方法获取
private static Logger log = LoggerFactory.getLogger(XxxController.class);
// 注解方式获取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";
}
<a href="${pageContext.request.contextPath}/文件名称/download">文件下载</a>
@RequestMapping("/download")
public ResponseEntity<byte[]> download(String fileName) {
// 调用父类文件下载方法
return this.fileDownLoad(fileName);
}
// 使用自定义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);
更多方法使用请参考项目中的示例代码



MIT License