New file |
| | |
| | | *.js linguist-language=java |
| | | *.css linguist-language=java |
| | | *.html linguist-language=java |
| | | *.btl linguist-language=java |
New file |
| | |
| | | # Compiled class file |
| | | *.class |
| | | *.iml |
| | | *.idea |
| | | target/ |
| | | logs/ |
| | | |
| | | # Log file |
| | | *.log |
| | | |
| | | # BlueJ files |
| | | *.ctxt |
| | | |
| | | # Mobile Tools for Java (J2ME) |
| | | .mtj.tmp/ |
| | | |
| | | # Package Files # |
| | | *.jar |
| | | *.war |
| | | *.ear |
| | | *.zip |
| | | *.tar.gz |
| | | *.rar |
| | | |
| | | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml |
| | | hs_err_pid* |
| | | |
| | | *velocity.log* |
| | | |
| | | # Eclipse # |
| | | .classpath |
| | | .project |
| | | .settings/ |
New file |
| | |
| | | Copyright 2018 StyleFeng |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
New file |
| | |
| | | # Guns V4.1 |
| | | |
| | | ## 介绍 |
| | | Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + mybatis-plus + beetl!Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作为一个后台管理系统的脚手架! 2018目标 `更简洁`,`更规范`! |
| | | |
| | | Guns v3.0新增rest api服务,提供对接服务端接口的支持,并利用jwt token鉴权机制给予客户端的访问权限,传输数据进行md5签名保证传输过程数据的安全性! |
| | | |
| | | ### Guns v4.1更新内容 |
| | | |
| | | > * guns-admin提供rest api服务,并以jwt方式鉴权,所有以`/gunsApi`开头的接口走这种鉴权方式,其他接口仍为shiro鉴权 |
| | | |
| | | ### Guns v4.0更新内容 |
| | | |
| | | > * spring boot升级到2.0版本! |
| | | > * 简化前端所有的html,js,css等资源文件,由11.8MB缩减为4.8MB! |
| | | > * 新增手动增加标签页的方法,Feng.newCrontab(href,menuName); |
| | | > * laydate时间插件和layer弹出层插件更新为官网最新,可以看着layui官网的文档直接开发啦! |
| | | > * 去掉animate动画效果,加快页面响应速度! |
| | | > * 修复登陆后重启应用造成404的bug! |
| | | > * 增强core模块的功能,拿来即用开发新的模块的后端管理系统! |
| | | > * 升级各个依赖包的版本! |
| | | > * 简化applicatioin.yml的配置,一些固定不变的配置写在core模块的default-config.properties! |
| | | > * 简化多数据源配置,简化mybatis-plus的配置! |
| | | > * 优化日志记录格式和策略,详情见logback-spring.xml! |
| | | |
| | | 此外,**更新Guns文档到《Guns技术文档 v2.0》** |
| | | |
| | | ## 最新Guns技术文档 |
| | | Guns框架有作者在业余时间整理的技术文档,详情点击[查看详情](https://gitee.com/naan1993/guns/wikis/pages?title=Guns%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3&parent=) |
| | | |
| | | ## 最新Guns视频教程 |
| | | Guns框架有作者在业余时间录制的视频教程,详情点击[教程介绍](https://gitee.com/naan1993/guns/wikis/pages?title=Guns%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B&parent=) |
| | | |
| | | ## 技术讨论 & [wiki地址](https://gitee.com/naan1993/guns/wikis/Home) |
| | | 如果对项目有任何疑问或者建议,欢迎加入Guns技术交流1群:254550081,Guns技术交流2群:684163663,Guns技术交流3群:207434260(加之前先看下文档guns-admin/doc/Guns技术文档 v1.0.pdf) |
| | | |
| | | ## 管理系统功能 |
| | | 1.用户管理 2.角色管理 3.部门管理 4.菜单管理 5.字典管理 6.业务日志 7.登录日志 8.监控管理 9.通知管理 10.代码生成 |
| | | |
| | | ## 项目特点 |
| | | 1. 基于SpringBoot,简化了大量项目配置和maven依赖,让您更专注于业务开发,独特的分包方式,代码多而不乱。 |
| | | 2. 完善的日志记录体系,可记录登录日志,业务操作日志(可记录操作前和操作后的数据),异常日志到数据库,通过@BussinessLog注解和LogObjectHolder.me().set()方法,业务操作日志可具体记录哪个用户,执行了哪些业务,修改了哪些数据,并且日志记录为异步执行,详情请见@BussinessLog注解和LogObjectHolder,LogManager,LogAop类。 |
| | | 3. 利用beetl模板引擎对前台页面进行封装和拆分,使臃肿的html代码变得简洁,更加易维护。 |
| | | 4. 对常用js插件进行二次封装,使js代码变得简洁,更加易维护,具体请见webapp/static/js/common文件夹内js代码。 |
| | | 5. 利用ehcache框架对经常调用的查询进行缓存,提升运行速度,具体请见ConstantFactory类中@Cacheable标记的方法。 |
| | | 6. controller层采用map + warpper方式的返回结果,返回给前端更为灵活的数据,具体参见com.stylefeng.guns.modular.system.warpper包中具体类。 |
| | | 7. 防止XSS攻击,通过XssFilter类对所有的输入的非法字符串进行过滤以及替换。 |
| | | 8. 简单可用的代码生成体系,通过SimpleTemplateEngine可生成带有主页跳转和增删改查的通用控制器、html页面以及相关的js,还可以生成Service和Dao,并且这些生成项都为可选的,通过ContextConfig下的一些列xxxSwitch开关,可灵活控制生成模板代码,让您把时间放在真正的业务上。 |
| | | 9. 控制器层统一的异常拦截机制,利用@ControllerAdvice统一对异常拦截,具体见com.stylefeng.guns.core.aop.GlobalExceptionHandler类。 |
| | | 10. 页面统一的js key-value单例模式写法,每个页面生成一个唯一的全局变量,提高js的利用效率,并且有效防止多个人员开发引起的函数名/类名冲突,并且可以更好地去维护代码。 |
| | | |
| | | ## 基于javabean方式的spring配置 |
| | | Guns以简洁为核心,抛弃了传统的易错,臃肿xml配置,采用javabean的方式配置spring,简化了项目的配置,如下示例为配置mybatis-plus和数据源: |
| | | ``` |
| | | @Configuration |
| | | @MapperScan(basePackages = {"com.stylefeng.guns.modular.*.dao", "com.stylefeng.guns.common.persistence.dao"}) |
| | | public class MybatisPlusConfig { |
| | | |
| | | @Autowired |
| | | DruidProperties druidProperties; |
| | | |
| | | /** |
| | | * mybatis-plus分页插件 |
| | | */ |
| | | @Bean |
| | | public PaginationInterceptor paginationInterceptor() { |
| | | PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); |
| | | paginationInterceptor.setDialectType(DBType.MYSQL.getDb()); |
| | | return paginationInterceptor; |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## 业务日志记录 |
| | | 日志记录采用aop(LogAop类)方式对所有包含@BussinessLog注解的方法进行aop切入,会记录下当前用户执行了哪些操作(即@BussinessLog value属性的内容),如果涉及到数据修改,会取当前http请求的所有requestParameters与LogObjectHolder类中缓存的Object对象的所有字段作比较(所以在编辑之前的获取详情接口中需要缓存被修改对象之前的字段信息),日志内容会异步存入数据库中(通过ScheduledThreadPoolExecutor类)。 |
| | | |
| | | ## beetl对前台页面的拆分与包装 |
| | | 例如,把主页拆分成三部分,每个部分单独一个页面,更加便于维护 |
| | | ``` |
| | | <!--左侧导航开始--> |
| | | @include("/common/_tab.html"){} |
| | | <!--左侧导航结束--> |
| | | |
| | | <!--右侧部分开始--> |
| | | @include("/common/_right.html"){} |
| | | <!--右侧部分结束--> |
| | | |
| | | <!--右侧边栏开始--> |
| | | @include("/common/_theme.html"){} |
| | | <!--右侧边栏结束--> |
| | | ``` |
| | | 以及对重复的html进行包装,使前端页面更加专注于业务实现,例如,把所有页面引用包进行提取 |
| | | ``` |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <meta charset="utf-8"> |
| | | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | | <meta name="renderer" content="webkit" /><!-- 让360浏览器默认选择webkit内核 --> |
| | | |
| | | <!-- 全局css --> |
| | | <link rel="shortcut icon" href="${ctxPath}/static/favicon.ico"> |
| | | <!-- 全局js --> |
| | | <script src="${ctxPath}/static/js/jquery.min.js?v=2.1.4"></script> |
| | | <body class="gray-bg"> |
| | | <div class="wrapper wrapper-content"> |
| | | ${layoutContent} |
| | | </div> |
| | | <script src="${ctxPath}/static/js/content.js?v=1.0.0"></script> |
| | | </body> |
| | | </html> |
| | | ``` |
| | | 开发页面时,只需编写如下代码即可 |
| | | ``` |
| | | @layout("/common/_container.html"){ |
| | | <div class="row"> |
| | | <div class="col-sm-12"> |
| | | <div class="ibox float-e-margins"> |
| | | <div class="ibox-title"> |
| | | <h5>部门管理</h5> |
| | | </div> |
| | | <div class="ibox-content"> |
| | | //自定义内容 |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <script src="${ctxPath}/static/modular/system/dept/dept.js"></script> |
| | | @} |
| | | ``` |
| | | 以上beetl的用法请参考beetl说明文档。 |
| | | |
| | | ## 对js常用代码的封装 |
| | | 在webapp/static/js/common目录中,有对常用js代码的封装,例如Feng.js,其中Feng.info(),Feng.success(),Feng.error()三个方法,分别封装了普通提示,成功提示,错误提示的代码,简化了layer提示层插件的使用。 |
| | | |
| | | ## 极简的图片上传方法 |
| | | guns对web-upload进行二次封装,让图片的上传功能呢只用2行代码即可实现,如下 |
| | | ``` |
| | | var avatarUp = new $WebUpload("avatar"); |
| | | avatarUp.init(); |
| | | ``` |
| | | 具体实现请参考static/js/common/web-upload-object.js |
| | | |
| | | ## 独创controller层,map+warpper返回方式 |
| | | map+warpper方式即为把controller层的返回结果使用BeanKit工具类把原有bean转化为Map的的形式(或者原有bean直接是map的形式),再用单独写的一个包装类再包装一次这个map,使里面的参数更加具体,更加有含义,下面举一个例子,例如,在返回给前台一个性别时,数据库查出来1是男2是女,假如直接返回给前台,那么前台显示的时候还需要增加一次判断,并且前后端分离开发时又增加了一次交流和文档的成本,但是采用warpper包装的形式,可以直接把返回结果包装一下,例如动态增加一个字段sexName直接返回给前台性别的中文名称即可。 |
| | | |
| | | ## 独创mybatis数据范围拦截器,实现对数据权限的过滤 |
| | | Guns的数据范围控制是指,对拥有相同角色的用户,根据部门的不同进行相应的数据筛选,如果部门不相同,那么有可能展示出的具体数据是不一致的.所以说Guns对数据范围控制是以部门id为单位来标识的,如何增加数据范围拦截呢?只需在相关的mapper接口的参数中增加一个DataScope对象即可,DataScope中有两个字段,scopeName用来标识sql语句中部门id的字段名称,例如deptiid或者id,另一个字段deptIds就是具体需要过滤的部门id的集合.拦截器原理如下:拦截mapper中包含DataScope对象的方法,获取其原始sql,并做一个包装限制部门id在deptIds范围内的数据进行展示. |
| | | |
| | | ## swagger api管理使用说明 |
| | | swagger会管理所有包含@ApiOperation注解的控制器方法,同时,可利用@ApiImplicitParams注解标记接口中的参数,具体用法请参考CodeController类中的用法。 |
| | | ``` |
| | | @ApiOperation("生成代码") |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "moduleName", value = "模块名称", required = true, dataType = "String"), |
| | | @ApiImplicitParam(name = "bizChName", value = "业务名称", required = true, dataType = "String"), |
| | | @ApiImplicitParam(name = "bizEnName", value = "业务英文名称", required = true, dataType = "String"), |
| | | @ApiImplicitParam(name = "path", value = "项目生成类路径", required = true, dataType = "String") |
| | | }) |
| | | @RequestMapping(value = "/generate", method = RequestMethod.POST) |
| | | ``` |
| | | |
| | | ## jwt token鉴权机制 |
| | | jwt token鉴权机制是指若需要请求服务器接口,必须通过AuthController获取一个请求令牌(jwt token),持有jwt token的用户才可以访问服务器的其他资源,如果没有此令牌,则访问接口会直接忽略,请求获取jwt token时,需要携带credenceName和credenceCode(可以是账号密码,可以是手机号验证码等等),校验credenceName和credenceCode成功后,会颁发给客户端一个jwt token还有一个随机字符串,用于传输过程中对数据进行签名用,签名机制请见下面介绍.基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息.这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利. |
| | | |
| | | ## 签名机制 |
| | | 签名机制是指客户端向服务端传输数据中,对传输数据进行md5加密,并且加密过程中利用Auth接口返回的随机字符串进行混淆加密,并把md5值同时附带给服务端,服务端通获取数据之后对数据再进行一次md5加密,若加密结果和客户端传来的数据一致,则认定客户端请求的数据是没有被篡改的,若不一致,则认为被加密的数据是被篡改的 |
| | | |
| | | ## 效果图 |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | | |
| | | ## 曾获荣誉 |
| | |  |
New file |
| | |
| | | <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"> |
| | | <parent> |
| | | <groupId>com.stylefeng</groupId> |
| | | <artifactId>guns-parent</artifactId> |
| | | <version>1.0.0</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | |
| | | <artifactId>guns-core</artifactId> |
| | | <packaging>jar</packaging> |
| | | |
| | | <name>guns-core</name> |
| | | <url>http://maven.apache.org</url> |
| | | |
| | | <dependencies> |
| | | |
| | | <!--通用依赖--> |
| | | <dependency> |
| | | <groupId>com.baomidou</groupId> |
| | | <artifactId>mybatisplus-spring-boot-starter</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.baomidou</groupId> |
| | | <artifactId>mybatis-plus</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.velocity</groupId> |
| | | <artifactId>velocity</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>mysql</groupId> |
| | | <artifactId>mysql-connector-java</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-jdbc</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>druid</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>fastjson</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.commons</groupId> |
| | | <artifactId>commons-lang3</artifactId> |
| | | </dependency> |
| | | |
| | | <!--web--> |
| | | <dependency> |
| | | <groupId>javax.servlet</groupId> |
| | | <artifactId>javax.servlet-api</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-web</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | |
| | | <!--aop--> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-aop</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | |
| | | <!--二维码--> |
| | | <dependency> |
| | | <groupId>com.google.zxing</groupId> |
| | | <artifactId>core</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | |
| | | <!--缓存--> |
| | | <dependency> |
| | | <groupId>org.ehcache</groupId> |
| | | <artifactId>ehcache</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-cache</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>net.sf.ehcache</groupId> |
| | | <artifactId>ehcache-core</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-configuration-processor</artifactId> |
| | | <optional>true</optional> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | <build> |
| | | <resources> |
| | | <resource> |
| | | <directory>src/main/resources</directory> |
| | | </resource> |
| | | </resources> |
| | | </build> |
| | | </project> |
New file |
| | |
| | | package com.stylefeng.guns.core; |
| | | |
| | | /** |
| | | * 此类用来获取core模块的包路径 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/12/5 下午12:44 |
| | | */ |
| | | public class CoreFlag { |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.aop; |
| | | |
| | | import com.stylefeng.guns.core.base.tips.ErrorTip; |
| | | import com.stylefeng.guns.core.exception.GunsException; |
| | | import com.stylefeng.guns.core.exception.GunsExceptionEnum; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.web.bind.annotation.ExceptionHandler; |
| | | import org.springframework.web.bind.annotation.ResponseBody; |
| | | import org.springframework.web.bind.annotation.ResponseStatus; |
| | | |
| | | /** |
| | | * 全局的的异常拦截器(拦截所有的控制器)(带有@RequestMapping注解的方法上都会拦截) |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月12日 下午3:19:56 |
| | | */ |
| | | public class BaseControllerExceptionHandler { |
| | | |
| | | private Logger log = LoggerFactory.getLogger(this.getClass()); |
| | | |
| | | /** |
| | | * 拦截业务异常 |
| | | */ |
| | | @ExceptionHandler(GunsException.class) |
| | | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) |
| | | @ResponseBody |
| | | public ErrorTip notFount(GunsException e) { |
| | | log.error("业务异常:", e); |
| | | return new ErrorTip(e.getCode(), e.getMessage()); |
| | | } |
| | | |
| | | /** |
| | | * 拦截未知的运行时异常 |
| | | */ |
| | | @ExceptionHandler(RuntimeException.class) |
| | | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) |
| | | @ResponseBody |
| | | public ErrorTip notFount(RuntimeException e) { |
| | | log.error("运行时异常:", e); |
| | | return new ErrorTip(GunsExceptionEnum.SERVER_ERROR.getCode(), GunsExceptionEnum.SERVER_ERROR.getMessage()); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.controller; |
| | | |
| | | import com.baomidou.mybatisplus.plugins.Page; |
| | | import com.stylefeng.guns.core.base.tips.SuccessTip; |
| | | import com.stylefeng.guns.core.base.warpper.BaseControllerWarpper; |
| | | import com.stylefeng.guns.core.page.PageInfoBT; |
| | | import com.stylefeng.guns.core.support.HttpKit; |
| | | import com.stylefeng.guns.core.util.FileUtil; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.http.ResponseEntity; |
| | | |
| | | import javax.servlet.http.Cookie; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import javax.servlet.http.HttpSession; |
| | | import java.io.UnsupportedEncodingException; |
| | | |
| | | public class BaseController { |
| | | |
| | | protected static String SUCCESS = "SUCCESS"; |
| | | protected static String ERROR = "ERROR"; |
| | | |
| | | protected static String REDIRECT = "redirect:"; |
| | | protected static String FORWARD = "forward:"; |
| | | |
| | | protected static SuccessTip SUCCESS_TIP = new SuccessTip(); |
| | | |
| | | protected HttpServletRequest getHttpServletRequest() { |
| | | return HttpKit.getRequest(); |
| | | } |
| | | |
| | | protected HttpServletResponse getHttpServletResponse() { |
| | | return HttpKit.getResponse(); |
| | | } |
| | | |
| | | protected HttpSession getSession() { |
| | | return HttpKit.getRequest().getSession(); |
| | | } |
| | | |
| | | protected HttpSession getSession(Boolean flag) { |
| | | return HttpKit.getRequest().getSession(flag); |
| | | } |
| | | |
| | | protected String getPara(String name) { |
| | | return HttpKit.getRequest().getParameter(name); |
| | | } |
| | | |
| | | protected void setAttr(String name, Object value) { |
| | | HttpKit.getRequest().setAttribute(name, value); |
| | | } |
| | | |
| | | protected Integer getSystemInvokCount() { |
| | | return (Integer) this.getHttpServletRequest().getServletContext().getAttribute("systemCount"); |
| | | } |
| | | |
| | | /** |
| | | * 把service层的分页信息,封装为bootstrap table通用的分页封装 |
| | | */ |
| | | protected <T> PageInfoBT<T> packForBT(Page<T> page) { |
| | | return new PageInfoBT<T>(page); |
| | | } |
| | | |
| | | /** |
| | | * 包装一个list,让list增加额外属性 |
| | | */ |
| | | protected Object warpObject(BaseControllerWarpper warpper) { |
| | | return warpper.warp(); |
| | | } |
| | | |
| | | /** |
| | | * 删除cookie |
| | | */ |
| | | protected void deleteCookieByName(String cookieName) { |
| | | Cookie[] cookies = this.getHttpServletRequest().getCookies(); |
| | | for (Cookie cookie : cookies) { |
| | | if (cookie.getName().equals(cookieName)) { |
| | | Cookie temp = new Cookie(cookie.getName(), ""); |
| | | temp.setMaxAge(0); |
| | | this.getHttpServletResponse().addCookie(temp); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 删除所有cookie |
| | | */ |
| | | protected void deleteAllCookie() { |
| | | Cookie[] cookies = this.getHttpServletRequest().getCookies(); |
| | | for (Cookie cookie : cookies) { |
| | | Cookie temp = new Cookie(cookie.getName(), ""); |
| | | temp.setMaxAge(0); |
| | | this.getHttpServletResponse().addCookie(temp); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 返回前台文件流 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月28日 下午2:53:19 |
| | | */ |
| | | protected ResponseEntity<byte[]> renderFile(String fileName, String filePath) { |
| | | byte[] bytes = FileUtil.toByteArray(filePath); |
| | | return renderFile(fileName, bytes); |
| | | } |
| | | |
| | | /** |
| | | * 返回前台文件流 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月28日 下午2:53:19 |
| | | */ |
| | | protected ResponseEntity<byte[]> renderFile(String fileName, byte[] fileBytes) { |
| | | String dfileName = null; |
| | | try { |
| | | dfileName = new String(fileName.getBytes("gb2312"), "iso8859-1"); |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); |
| | | headers.setContentDispositionFormData("attachment", dfileName); |
| | | return new ResponseEntity<byte[]>(fileBytes, headers, HttpStatus.CREATED); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.controller; |
| | | |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.ui.Model; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | |
| | | /** |
| | | * 全局的控制器 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月13日 下午11:04:45 |
| | | */ |
| | | @Controller |
| | | @RequestMapping("/global") |
| | | public class GlobalController { |
| | | |
| | | /** |
| | | * 跳转到404页面 |
| | | * |
| | | * @author fengshuonan |
| | | */ |
| | | @RequestMapping(path = "/error") |
| | | public String errorPage() { |
| | | return "/404.html"; |
| | | } |
| | | |
| | | /** |
| | | * 跳转到session超时页面 |
| | | * |
| | | * @author fengshuonan |
| | | */ |
| | | @RequestMapping(path = "/sessionError") |
| | | public String errorPageInfo(Model model) { |
| | | model.addAttribute("tips", "session超时"); |
| | | return "/login.html"; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.controller; |
| | | |
| | | import org.springframework.web.servlet.View; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 错误页面的默认跳转(例如请求404的时候,默认走这个视图解析器) |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-21 11:34 |
| | | */ |
| | | public class GunsErrorView implements View { |
| | | |
| | | @Override |
| | | public String getContentType() { |
| | | return "text/html"; |
| | | } |
| | | |
| | | @Override |
| | | public void render(Map<String, ?> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { |
| | | httpServletRequest.getRequestDispatcher("/global/error").forward(httpServletRequest, httpServletResponse); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.tips; |
| | | |
| | | /** |
| | | * 返回给前台的错误提示 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月12日 下午5:05:22 |
| | | */ |
| | | public class ErrorTip extends Tip { |
| | | |
| | | public ErrorTip(int code, String message) { |
| | | super(); |
| | | this.code = code; |
| | | this.message = message; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.tips; |
| | | |
| | | /** |
| | | * 返回给前台的成功提示 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月12日 下午5:05:22 |
| | | */ |
| | | public class SuccessTip extends Tip { |
| | | |
| | | public SuccessTip(){ |
| | | super.code = 200; |
| | | super.message = "操作成功"; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.tips; |
| | | |
| | | /** |
| | | * 返回给前台的提示(最终转化为json形式) |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017年1月11日 下午11:58:00 |
| | | */ |
| | | public abstract class Tip { |
| | | |
| | | protected int code; |
| | | protected String message; |
| | | |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(int code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.warpper; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 控制器查询结果的包装类基类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月13日 下午10:49:36 |
| | | */ |
| | | public abstract class BaseControllerWarpper { |
| | | |
| | | public Object obj = null; |
| | | |
| | | public BaseControllerWarpper(Object obj) { |
| | | this.obj = obj; |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public Object warp() { |
| | | if (this.obj instanceof List) { |
| | | List<Map<String, Object>> list = (List<Map<String, Object>>) this.obj; |
| | | for (Map<String, Object> map : list) { |
| | | warpTheMap(map); |
| | | } |
| | | return list; |
| | | } else if (this.obj instanceof Map) { |
| | | Map<String, Object> map = (Map<String, Object>) this.obj; |
| | | warpTheMap(map); |
| | | return map; |
| | | } else { |
| | | return this.obj; |
| | | } |
| | | } |
| | | |
| | | protected abstract void warpTheMap(Map<String, Object> map); |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | |
| | | /** |
| | | * 缓存工厂基类 |
| | | */ |
| | | public abstract class BaseCacheFactory implements ICache { |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public <T> T get(String cacheName, Object key, ILoader iLoader) { |
| | | Object data = get(cacheName, key); |
| | | if (data == null) { |
| | | data = iLoader.load(); |
| | | put(cacheName, key, data); |
| | | } |
| | | return (T) data; |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass) { |
| | | Object data = get(cacheName, key); |
| | | if (data == null) { |
| | | try { |
| | | ILoader dataLoader = iLoaderClass.newInstance(); |
| | | data = dataLoader.load(); |
| | | put(cacheName, key, data); |
| | | } catch (Exception e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | return (T) data; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 缓存工具类 |
| | | */ |
| | | public class CacheKit { |
| | | |
| | | private static ICache defaultCacheFactory = new EhcacheFactory(); |
| | | |
| | | public static void put(String cacheName, Object key, Object value) { |
| | | defaultCacheFactory.put(cacheName, key, value); |
| | | } |
| | | |
| | | public static <T> T get(String cacheName, Object key) { |
| | | return defaultCacheFactory.get(cacheName, key); |
| | | } |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | public static List getKeys(String cacheName) { |
| | | return defaultCacheFactory.getKeys(cacheName); |
| | | } |
| | | |
| | | public static void remove(String cacheName, Object key) { |
| | | defaultCacheFactory.remove(cacheName, key); |
| | | } |
| | | |
| | | public static void removeAll(String cacheName) { |
| | | defaultCacheFactory.removeAll(cacheName); |
| | | } |
| | | |
| | | public static <T> T get(String cacheName, Object key, ILoader iLoader) { |
| | | return defaultCacheFactory.get(cacheName, key, iLoader); |
| | | } |
| | | |
| | | public static <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass) { |
| | | return defaultCacheFactory.get(cacheName, key, iLoaderClass); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2011-2016, James Zhan 詹波 (jfinal@126.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | import net.sf.ehcache.Cache; |
| | | import net.sf.ehcache.CacheManager; |
| | | import net.sf.ehcache.Element; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * Ehcache缓存工厂 |
| | | */ |
| | | public class EhcacheFactory extends BaseCacheFactory { |
| | | |
| | | private static CacheManager cacheManager; |
| | | private static volatile Object locker = new Object(); |
| | | private static final Logger log = LoggerFactory.getLogger(EhcacheFactory.class); |
| | | |
| | | private static CacheManager getCacheManager() { |
| | | if (cacheManager == null) { |
| | | synchronized (EhcacheFactory.class) { |
| | | if (cacheManager == null) { |
| | | cacheManager = CacheManager.create(); |
| | | } |
| | | } |
| | | } |
| | | return cacheManager; |
| | | } |
| | | |
| | | static Cache getOrAddCache(String cacheName) { |
| | | CacheManager cacheManager = getCacheManager(); |
| | | Cache cache = cacheManager.getCache(cacheName); |
| | | if (cache == null) { |
| | | synchronized(locker) { |
| | | cache = cacheManager.getCache(cacheName); |
| | | if (cache == null) { |
| | | log.warn("无法找到缓存 [" + cacheName + "]的配置, 使用默认配置."); |
| | | cacheManager.addCacheIfAbsent(cacheName); |
| | | cache = cacheManager.getCache(cacheName); |
| | | log.debug("缓存 [" + cacheName + "] 启动."); |
| | | } |
| | | } |
| | | } |
| | | return cache; |
| | | } |
| | | |
| | | public void put(String cacheName, Object key, Object value) { |
| | | getOrAddCache(cacheName).put(new Element(key, value)); |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public <T> T get(String cacheName, Object key) { |
| | | Element element = getOrAddCache(cacheName).get(key); |
| | | return element != null ? (T)element.getObjectValue() : null; |
| | | } |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | public List getKeys(String cacheName) { |
| | | return getOrAddCache(cacheName).getKeys(); |
| | | } |
| | | |
| | | public void remove(String cacheName, Object key) { |
| | | getOrAddCache(cacheName).remove(key); |
| | | } |
| | | |
| | | public void removeAll(String cacheName) { |
| | | getOrAddCache(cacheName).removeAll(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 通用缓存接口 |
| | | */ |
| | | public interface ICache { |
| | | |
| | | void put(String cacheName, Object key, Object value); |
| | | |
| | | <T> T get(String cacheName, Object key); |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | List getKeys(String cacheName); |
| | | |
| | | void remove(String cacheName, Object key); |
| | | |
| | | void removeAll(String cacheName); |
| | | |
| | | <T> T get(String cacheName, Object key, ILoader iLoader); |
| | | |
| | | <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass); |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | /** |
| | | * 数据重载 |
| | | */ |
| | | public interface ILoader { |
| | | Object load(); |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config; |
| | | |
| | | import com.alibaba.fastjson.serializer.SerializeConfig; |
| | | import com.alibaba.fastjson.serializer.SerializerFeature; |
| | | import com.alibaba.fastjson.serializer.ToStringSerializer; |
| | | import com.alibaba.fastjson.serializer.ValueFilter; |
| | | import com.alibaba.fastjson.support.config.FastJsonConfig; |
| | | import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.http.MediaType; |
| | | |
| | | import java.math.BigInteger; |
| | | import java.nio.charset.Charset; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * fastjson配置类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-23 22:56 |
| | | */ |
| | | @Configuration("defaultFastjsonConfig") |
| | | @ConditionalOnClass(com.alibaba.fastjson.JSON.class) |
| | | @ConditionalOnMissingBean(FastJsonHttpMessageConverter.class) |
| | | @ConditionalOnWebApplication |
| | | public class DefaultFastjsonConfig { |
| | | |
| | | @Bean |
| | | public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() { |
| | | FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); |
| | | converter.setFastJsonConfig(fastjsonConfig()); |
| | | converter.setSupportedMediaTypes(getSupportedMediaType()); |
| | | return converter; |
| | | } |
| | | |
| | | /** |
| | | * fastjson的配置 |
| | | */ |
| | | public FastJsonConfig fastjsonConfig() { |
| | | FastJsonConfig fastJsonConfig = new FastJsonConfig(); |
| | | fastJsonConfig.setSerializerFeatures( |
| | | SerializerFeature.PrettyFormat, |
| | | SerializerFeature.WriteMapNullValue, |
| | | SerializerFeature.WriteEnumUsingToString |
| | | ); |
| | | fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | ValueFilter valueFilter = new ValueFilter() { |
| | | public Object process(Object o, String s, Object o1) { |
| | | if (null == o1) { |
| | | o1 = ""; |
| | | } |
| | | return o1; |
| | | } |
| | | }; |
| | | fastJsonConfig.setCharset(Charset.forName("utf-8")); |
| | | fastJsonConfig.setSerializeFilters(valueFilter); |
| | | |
| | | //解决Long转json精度丢失的问题 |
| | | SerializeConfig serializeConfig = SerializeConfig.globalInstance; |
| | | serializeConfig.put(BigInteger.class, ToStringSerializer.instance); |
| | | serializeConfig.put(Long.class, ToStringSerializer.instance); |
| | | serializeConfig.put(Long.TYPE, ToStringSerializer.instance); |
| | | fastJsonConfig.setSerializeConfig(serializeConfig); |
| | | return fastJsonConfig; |
| | | } |
| | | |
| | | /** |
| | | * 支持的mediaType类型 |
| | | */ |
| | | public List<MediaType> getSupportedMediaType() { |
| | | ArrayList<MediaType> mediaTypes = new ArrayList<>(); |
| | | mediaTypes.add(MediaType.APPLICATION_JSON_UTF8); |
| | | return mediaTypes; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config; |
| | | |
| | | import com.stylefeng.guns.core.mutidatasource.aop.MultiSourceExAop; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | /** |
| | | * 多数据源配置 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/20 21:58 |
| | | */ |
| | | @Configuration |
| | | @ConditionalOnProperty(prefix = "guns", name = "muti-datasource-open", havingValue = "true") |
| | | public class DefaultMultiConfig { |
| | | |
| | | @Bean |
| | | public MultiSourceExAop multiSourceExAop() { |
| | | return new MultiSourceExAop(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config; |
| | | |
| | | import com.stylefeng.guns.core.config.properties.DruidProperties; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.context.annotation.PropertySource; |
| | | |
| | | /** |
| | | * 默认的配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2018-01-07 12:33 |
| | | */ |
| | | @Configuration |
| | | @PropertySource("classpath:/default-config.properties") |
| | | public class DefaultProperties { |
| | | |
| | | @Bean |
| | | @ConfigurationProperties(prefix = "spring.datasource") |
| | | public DruidProperties druidProperties() { |
| | | return new DruidProperties(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config; |
| | | |
| | | import com.stylefeng.guns.core.base.controller.GunsErrorView; |
| | | import com.stylefeng.guns.core.exception.GunsException; |
| | | import com.stylefeng.guns.core.exception.GunsExceptionEnum; |
| | | import com.stylefeng.guns.core.util.DateUtil; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.core.convert.converter.Converter; |
| | | import org.springframework.core.convert.support.GenericConversionService; |
| | | import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; |
| | | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; |
| | | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; |
| | | |
| | | import javax.annotation.PostConstruct; |
| | | import java.util.Date; |
| | | import java.util.regex.Pattern; |
| | | |
| | | @Configuration |
| | | public class DefaultWebConfig extends WebMvcConfigurationSupport { |
| | | |
| | | @Autowired |
| | | private RequestMappingHandlerAdapter handlerAdapter; |
| | | |
| | | @Bean("error") |
| | | public GunsErrorView error() { |
| | | return new GunsErrorView(); |
| | | } |
| | | |
| | | @PostConstruct |
| | | public void addConversionConfig() { |
| | | ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) handlerAdapter.getWebBindingInitializer(); |
| | | GenericConversionService genericConversionService = (GenericConversionService) initializer.getConversionService(); |
| | | genericConversionService.addConverter(new StringToDateConverter()); |
| | | } |
| | | |
| | | public class StringToDateConverter implements Converter<String, Date> { |
| | | |
| | | @Override |
| | | public Date convert(String dateString) { |
| | | |
| | | String patternDate = "\\d{4}-\\d{1,2}-\\d{1,2}"; |
| | | String patternTimeMinutes = "\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}"; |
| | | String patternTimeSeconds = "\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}"; |
| | | |
| | | boolean dateFlag = Pattern.matches(patternDate, dateString); |
| | | boolean timeMinutesFlag = Pattern.matches(patternTimeMinutes, dateString); |
| | | boolean timeSecondsFlag = Pattern.matches(patternTimeSeconds, dateString); |
| | | |
| | | if (dateFlag) { |
| | | return DateUtil.parseDate(dateString); |
| | | } else if (timeMinutesFlag) { |
| | | return DateUtil.parseTimeMinutes(dateString); |
| | | } else if (timeSecondsFlag) { |
| | | return DateUtil.parseTime(dateString); |
| | | } else { |
| | | throw new GunsException(GunsExceptionEnum.INVLIDE_DATE_STRING); |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
New file |
| | |
| | | package com.stylefeng.guns.core.config.properties; |
| | | |
| | | import com.alibaba.druid.pool.DruidDataSource; |
| | | |
| | | import java.sql.SQLException; |
| | | |
| | | /** |
| | | * <p>数据库数据源配置</p> |
| | | * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在"application.yml"中配置即可</p> |
| | | * @author stylefeng |
| | | * @date 2017-05-21 11:18 |
| | | */ |
| | | public class DruidProperties { |
| | | |
| | | private String url = "jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull"; |
| | | |
| | | private String username = "root"; |
| | | |
| | | private String password = "root"; |
| | | |
| | | private String driverClassName = "com.mysql.cj.jdbc.Driver"; |
| | | |
| | | private Integer initialSize = 2; |
| | | |
| | | private Integer minIdle = 1; |
| | | |
| | | private Integer maxActive = 20; |
| | | |
| | | private Integer maxWait = 60000; |
| | | |
| | | private Integer timeBetweenEvictionRunsMillis = 60000; |
| | | |
| | | private Integer minEvictableIdleTimeMillis = 300000; |
| | | |
| | | private String validationQuery = "SELECT 'x'"; |
| | | |
| | | private Boolean testWhileIdle = true; |
| | | |
| | | private Boolean testOnBorrow = false; |
| | | |
| | | private Boolean testOnReturn = false; |
| | | |
| | | private Boolean poolPreparedStatements = true; |
| | | |
| | | private Integer maxPoolPreparedStatementPerConnectionSize = 20; |
| | | |
| | | private String filters = "stat"; |
| | | |
| | | public void config(DruidDataSource dataSource) { |
| | | |
| | | dataSource.setUrl(url); |
| | | dataSource.setUsername(username); |
| | | dataSource.setPassword(password); |
| | | |
| | | dataSource.setDriverClassName(driverClassName); |
| | | dataSource.setInitialSize(initialSize); //定义初始连接数 |
| | | dataSource.setMinIdle(minIdle); //最小空闲 |
| | | dataSource.setMaxActive(maxActive); //定义最大连接数 |
| | | dataSource.setMaxWait(maxWait); //最长等待时间 |
| | | |
| | | // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 |
| | | dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); |
| | | |
| | | // 配置一个连接在池中最小生存的时间,单位是毫秒 |
| | | dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); |
| | | dataSource.setValidationQuery(validationQuery); |
| | | dataSource.setTestWhileIdle(testWhileIdle); |
| | | dataSource.setTestOnBorrow(testOnBorrow); |
| | | dataSource.setTestOnReturn(testOnReturn); |
| | | |
| | | // 打开PSCache,并且指定每个连接上PSCache的大小 |
| | | dataSource.setPoolPreparedStatements(poolPreparedStatements); |
| | | dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); |
| | | |
| | | try { |
| | | dataSource.setFilters(filters); |
| | | } catch (SQLException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public String getUsername() { |
| | | return username; |
| | | } |
| | | |
| | | public void setUsername(String username) { |
| | | this.username = username; |
| | | } |
| | | |
| | | public String getPassword() { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) { |
| | | this.password = password; |
| | | } |
| | | |
| | | public String getDriverClassName() { |
| | | return driverClassName; |
| | | } |
| | | |
| | | public void setDriverClassName(String driverClassName) { |
| | | this.driverClassName = driverClassName; |
| | | } |
| | | |
| | | public Integer getInitialSize() { |
| | | return initialSize; |
| | | } |
| | | |
| | | public void setInitialSize(Integer initialSize) { |
| | | this.initialSize = initialSize; |
| | | } |
| | | |
| | | public Integer getMinIdle() { |
| | | return minIdle; |
| | | } |
| | | |
| | | public void setMinIdle(Integer minIdle) { |
| | | this.minIdle = minIdle; |
| | | } |
| | | |
| | | public Integer getMaxActive() { |
| | | return maxActive; |
| | | } |
| | | |
| | | public void setMaxActive(Integer maxActive) { |
| | | this.maxActive = maxActive; |
| | | } |
| | | |
| | | public Integer getMaxWait() { |
| | | return maxWait; |
| | | } |
| | | |
| | | public void setMaxWait(Integer maxWait) { |
| | | this.maxWait = maxWait; |
| | | } |
| | | |
| | | public Integer getTimeBetweenEvictionRunsMillis() { |
| | | return timeBetweenEvictionRunsMillis; |
| | | } |
| | | |
| | | public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) { |
| | | this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; |
| | | } |
| | | |
| | | public Integer getMinEvictableIdleTimeMillis() { |
| | | return minEvictableIdleTimeMillis; |
| | | } |
| | | |
| | | public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) { |
| | | this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; |
| | | } |
| | | |
| | | public String getValidationQuery() { |
| | | return validationQuery; |
| | | } |
| | | |
| | | public void setValidationQuery(String validationQuery) { |
| | | this.validationQuery = validationQuery; |
| | | } |
| | | |
| | | public Boolean getTestWhileIdle() { |
| | | return testWhileIdle; |
| | | } |
| | | |
| | | public void setTestWhileIdle(Boolean testWhileIdle) { |
| | | this.testWhileIdle = testWhileIdle; |
| | | } |
| | | |
| | | public Boolean getTestOnBorrow() { |
| | | return testOnBorrow; |
| | | } |
| | | |
| | | public void setTestOnBorrow(Boolean testOnBorrow) { |
| | | this.testOnBorrow = testOnBorrow; |
| | | } |
| | | |
| | | public Boolean getTestOnReturn() { |
| | | return testOnReturn; |
| | | } |
| | | |
| | | public void setTestOnReturn(Boolean testOnReturn) { |
| | | this.testOnReturn = testOnReturn; |
| | | } |
| | | |
| | | public Boolean getPoolPreparedStatements() { |
| | | return poolPreparedStatements; |
| | | } |
| | | |
| | | public void setPoolPreparedStatements(Boolean poolPreparedStatements) { |
| | | this.poolPreparedStatements = poolPreparedStatements; |
| | | } |
| | | |
| | | public Integer getMaxPoolPreparedStatementPerConnectionSize() { |
| | | return maxPoolPreparedStatementPerConnectionSize; |
| | | } |
| | | |
| | | public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) { |
| | | this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; |
| | | } |
| | | |
| | | public String getFilters() { |
| | | return filters; |
| | | } |
| | | |
| | | public void setFilters(String filters) { |
| | | this.filters = filters; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config.properties; |
| | | |
| | | import com.alibaba.druid.pool.DruidDataSource; |
| | | |
| | | /** |
| | | * 默认多数据源配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-08-16 10:02 |
| | | */ |
| | | public class MutiDataSourceProperties { |
| | | |
| | | private String url = "jdbc:mysql://127.0.0.1:3306/biz?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull"; |
| | | |
| | | private String username = "root"; |
| | | |
| | | private String password = "root"; |
| | | |
| | | private String driverClassName = "com.mysql.cj.jdbc.Driver"; |
| | | |
| | | private String validationQuery = "SELECT 'x'"; |
| | | |
| | | private String[] dataSourceNames = {"dataSourceGuns", "dataSourceBiz"}; |
| | | |
| | | public void config(DruidDataSource dataSource) { |
| | | dataSource.setUrl(url); |
| | | dataSource.setUsername(username); |
| | | dataSource.setPassword(password); |
| | | dataSource.setDriverClassName(driverClassName); |
| | | dataSource.setValidationQuery(validationQuery); |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public String getUsername() { |
| | | return username; |
| | | } |
| | | |
| | | public void setUsername(String username) { |
| | | this.username = username; |
| | | } |
| | | |
| | | public String getPassword() { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) { |
| | | this.password = password; |
| | | } |
| | | |
| | | public String getDriverClassName() { |
| | | return driverClassName; |
| | | } |
| | | |
| | | public void setDriverClassName(String driverClassName) { |
| | | this.driverClassName = driverClassName; |
| | | } |
| | | |
| | | public String getValidationQuery() { |
| | | return validationQuery; |
| | | } |
| | | |
| | | public void setValidationQuery(String validationQuery) { |
| | | this.validationQuery = validationQuery; |
| | | } |
| | | |
| | | public String[] getDataSourceNames() { |
| | | return dataSourceNames; |
| | | } |
| | | |
| | | public void setDataSourceNames(String[] dataSourceNames) { |
| | | this.dataSourceNames = dataSourceNames; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.constant; |
| | | |
| | | /** |
| | | * 是否是菜单的枚举 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年6月1日22:50:11 |
| | | */ |
| | | public enum IsMenu { |
| | | |
| | | YES(1, "是"), |
| | | NO(0, "不是"); //不是菜单的是按钮 |
| | | |
| | | int code; |
| | | String message; |
| | | |
| | | IsMenu(int code, String message) { |
| | | this.code = code; |
| | | this.message = message; |
| | | } |
| | | |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(int code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | |
| | | public static String valueOf(Integer status) { |
| | | if (status == null) { |
| | | return ""; |
| | | } else { |
| | | for (IsMenu s : IsMenu.values()) { |
| | | if (s.getCode() == status) { |
| | | return s.getMessage(); |
| | | } |
| | | } |
| | | return ""; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.datascope; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 数据范围 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-07-23 22:19 |
| | | */ |
| | | public class DataScope { |
| | | |
| | | /** |
| | | * 限制范围的字段名称 |
| | | */ |
| | | private String scopeName = "deptid"; |
| | | |
| | | /** |
| | | * 具体的数据范围 |
| | | */ |
| | | private List<Integer> deptIds; |
| | | |
| | | public DataScope() { |
| | | } |
| | | |
| | | public DataScope(List<Integer> deptIds) { |
| | | this.deptIds = deptIds; |
| | | } |
| | | |
| | | public DataScope(String scopeName, List<Integer> deptIds) { |
| | | this.scopeName = scopeName; |
| | | this.deptIds = deptIds; |
| | | } |
| | | |
| | | public List<Integer> getDeptIds() { |
| | | return deptIds; |
| | | } |
| | | |
| | | public void setDeptIds(List<Integer> deptIds) { |
| | | this.deptIds = deptIds; |
| | | } |
| | | |
| | | public String getScopeName() { |
| | | return scopeName; |
| | | } |
| | | |
| | | public void setScopeName(String scopeName) { |
| | | this.scopeName = scopeName; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.datascope; |
| | | |
| | | |
| | | import com.baomidou.mybatisplus.toolkit.PluginUtils; |
| | | import com.stylefeng.guns.core.support.CollectionKit; |
| | | import org.apache.ibatis.executor.statement.StatementHandler; |
| | | import org.apache.ibatis.mapping.BoundSql; |
| | | import org.apache.ibatis.mapping.MappedStatement; |
| | | import org.apache.ibatis.mapping.SqlCommandType; |
| | | import org.apache.ibatis.plugin.*; |
| | | import org.apache.ibatis.reflection.MetaObject; |
| | | import org.apache.ibatis.reflection.SystemMetaObject; |
| | | |
| | | import java.sql.Connection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Properties; |
| | | |
| | | /** |
| | | * 数据范围的拦截器 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-07-23 21:26 |
| | | */ |
| | | @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) |
| | | public class DataScopeInterceptor implements Interceptor { |
| | | |
| | | @Override |
| | | public Object intercept(Invocation invocation) throws Throwable { |
| | | StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget()); |
| | | MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); |
| | | MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); |
| | | |
| | | if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) { |
| | | return invocation.proceed(); |
| | | } |
| | | |
| | | BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); |
| | | String originalSql = boundSql.getSql(); |
| | | Object parameterObject = boundSql.getParameterObject(); |
| | | |
| | | //查找参数中包含DataScope类型的参数 |
| | | DataScope dataScope = findDataScopeObject(parameterObject); |
| | | |
| | | if (dataScope == null) { |
| | | return invocation.proceed(); |
| | | } else { |
| | | String scopeName = dataScope.getScopeName(); |
| | | List<Integer> deptIds = dataScope.getDeptIds(); |
| | | String join = CollectionKit.join(deptIds, ","); |
| | | originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")"; |
| | | metaStatementHandler.setValue("delegate.boundSql.sql", originalSql); |
| | | return invocation.proceed(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 查找参数是否包括DataScope对象 |
| | | */ |
| | | public DataScope findDataScopeObject(Object parameterObj) { |
| | | if (parameterObj instanceof DataScope) { |
| | | return (DataScope) parameterObj; |
| | | } else if (parameterObj instanceof Map) { |
| | | for (Object val : ((Map<?, ?>) parameterObj).values()) { |
| | | if (val instanceof DataScope) { |
| | | return (DataScope) val; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public Object plugin(Object target) { |
| | | return Plugin.wrap(target, this); |
| | | } |
| | | |
| | | @Override |
| | | public void setProperties(Properties properties) { |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.db; |
| | | |
| | | import com.baomidou.mybatisplus.mapper.BaseMapper; |
| | | import com.stylefeng.guns.core.util.SpringContextHolder; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | | * 便捷数据库操作类 |
| | | * <p> |
| | | * <p> |
| | | * 本类的使用情景: |
| | | * <p> |
| | | * 1.单纯想创建现有的Mapper |
| | | * <p>例如: |
| | | * Db.getMapper(UserLoginMapper.class).selectById("14779707158513204");<br> |
| | | * <p> |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月22日 下午8:07:17 |
| | | */ |
| | | @SuppressWarnings("all") |
| | | public class Db<T> { |
| | | |
| | | /** |
| | | * 每个Db类,包装一个Mapper接口,这个clazz就是接口的类类型,例如UserMapper.class |
| | | */ |
| | | private Class<T> clazz; |
| | | |
| | | /** |
| | | * Mapper的父类接口 |
| | | */ |
| | | private BaseMapper<?> baseMapper; |
| | | |
| | | /** |
| | | * 私有构造方法,不允许自己创建 |
| | | */ |
| | | private Db(Class clazz) { |
| | | this.clazz = clazz; |
| | | this.baseMapper = (BaseMapper<?>) SpringContextHolder.getBean(clazz); |
| | | } |
| | | |
| | | /** |
| | | * <p> |
| | | * 创建包含指定mapper的Db工具类,使用本类的第一种用法 |
| | | * |
| | | * @param clazz mapper的类类型 |
| | | * @date 2017年2月22日 下午10:09:31 |
| | | */ |
| | | public static <T> Db<T> create(Class<T> clazz) { |
| | | return new Db<T>(clazz); |
| | | } |
| | | |
| | | /** |
| | | * <p> |
| | | * 获取一个mapper的快捷方法 |
| | | * |
| | | * @param clazz mapper类的类对象 |
| | | * @date 2017年2月22日 下午10:31:35 |
| | | */ |
| | | public BaseMapper<?> getMapper() { |
| | | return this.baseMapper; |
| | | } |
| | | |
| | | /** |
| | | * <p> |
| | | * 获取一个mapper的快捷方法 |
| | | * |
| | | * @param clazz mapper类的类对象 |
| | | * @date 2017年2月22日 下午10:31:35 |
| | | */ |
| | | public static <T> T getMapper(Class<T> clazz) { |
| | | return SpringContextHolder.getBean(clazz); |
| | | } |
| | | |
| | | /** |
| | | * 通过一个条件获取数据库中的一条记录(会返回null) |
| | | * |
| | | * @date 2017年2月22日 下午10:45:51 |
| | | */ |
| | | public <E> E selectOneByCon(String condition, Object value) { |
| | | List<?> results = selectOneByConList(condition, value); |
| | | if (results != null && results.size() > 0) { |
| | | return (E) results.get(0); |
| | | } else { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 通过一个条件获取一堆记录(会返回null) |
| | | * |
| | | * @date 2017年2月22日 下午10:45:51 |
| | | */ |
| | | public <E> List<E> selectOneByConList(String condition, Object value) { |
| | | HashMap<String, Object> conditionMap = new HashMap<String, Object>(); |
| | | conditionMap.put(condition, value); |
| | | |
| | | List<E> results = (List<E>) this.baseMapper.selectByMap(conditionMap); |
| | | if (results == null || results.size() == 0) { |
| | | return null; |
| | | } else { |
| | | return results; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.exception; |
| | | |
| | | /** |
| | | * 封装guns的异常 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/12/28 下午10:32 |
| | | */ |
| | | public class GunsException extends RuntimeException { |
| | | |
| | | private Integer code; |
| | | |
| | | private String message; |
| | | |
| | | public GunsException(ServiceExceptionEnum serviceExceptionEnum) { |
| | | this.code = serviceExceptionEnum.getCode(); |
| | | this.message = serviceExceptionEnum.getMessage(); |
| | | } |
| | | |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(Integer code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | @Override |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.exception; |
| | | |
| | | /** |
| | | * Guns异常枚举 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/12/28 下午10:33 |
| | | */ |
| | | public enum GunsExceptionEnum implements ServiceExceptionEnum { |
| | | |
| | | /** |
| | | * 其他 |
| | | */ |
| | | INVLIDE_DATE_STRING(400, "输入日期格式不对"), |
| | | |
| | | /** |
| | | * 其他 |
| | | */ |
| | | WRITE_ERROR(500, "渲染界面错误"), |
| | | |
| | | /** |
| | | * 文件上传 |
| | | */ |
| | | FILE_READING_ERROR(400, "FILE_READING_ERROR!"), |
| | | FILE_NOT_FOUND(400, "FILE_NOT_FOUND!"), |
| | | |
| | | /** |
| | | * 错误的请求 |
| | | */ |
| | | REQUEST_NULL(400, "请求有错误"), |
| | | SERVER_ERROR(500, "服务器异常"); |
| | | |
| | | GunsExceptionEnum(int code, String message) { |
| | | this.code = code; |
| | | this.message = message; |
| | | } |
| | | |
| | | private Integer code; |
| | | |
| | | private String message; |
| | | |
| | | @Override |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(Integer code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | @Override |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.exception; |
| | | |
| | | /** |
| | | * 抽象接口 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-12-28-下午10:27 |
| | | */ |
| | | public interface ServiceExceptionEnum { |
| | | |
| | | /** |
| | | * 获取异常编码 |
| | | */ |
| | | Integer getCode(); |
| | | |
| | | /** |
| | | * 获取异常信息 |
| | | */ |
| | | String getMessage(); |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.mutidatasource; |
| | | |
| | | /** |
| | | * datasource的上下文 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年3月5日 上午9:10:58 |
| | | */ |
| | | public class DataSourceContextHolder { |
| | | |
| | | private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); |
| | | |
| | | /** |
| | | * 设置数据源类型 |
| | | * |
| | | * @param dataSourceType 数据库类型 |
| | | */ |
| | | public static void setDataSourceType(String dataSourceType) { |
| | | contextHolder.set(dataSourceType); |
| | | } |
| | | |
| | | /** |
| | | * 获取数据源类型 |
| | | */ |
| | | public static String getDataSourceType() { |
| | | return contextHolder.get(); |
| | | } |
| | | |
| | | /** |
| | | * 清除数据源类型 |
| | | */ |
| | | public static void clearDataSourceType() { |
| | | contextHolder.remove(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.mutidatasource; |
| | | |
| | | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; |
| | | |
| | | /** |
| | | * 动态数据源 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年3月5日 上午9:11:49 |
| | | */ |
| | | public class DynamicDataSource extends AbstractRoutingDataSource { |
| | | |
| | | @Override |
| | | protected Object determineCurrentLookupKey() { |
| | | return DataSourceContextHolder.getDataSourceType(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.mutidatasource.annotion; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * |
| | | * 多数据源标识 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年3月5日 上午9:44:24 |
| | | */ |
| | | @Inherited |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Target({ ElementType.METHOD }) |
| | | public @interface DataSource { |
| | | |
| | | String name() default ""; |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.mutidatasource.aop; |
| | | |
| | | import com.stylefeng.guns.core.mutidatasource.DataSourceContextHolder; |
| | | import com.stylefeng.guns.core.mutidatasource.annotion.DataSource; |
| | | import com.stylefeng.guns.core.config.properties.MutiDataSourceProperties; |
| | | import org.aspectj.lang.ProceedingJoinPoint; |
| | | import org.aspectj.lang.Signature; |
| | | import org.aspectj.lang.annotation.Around; |
| | | import org.aspectj.lang.annotation.Aspect; |
| | | import org.aspectj.lang.annotation.Pointcut; |
| | | import org.aspectj.lang.reflect.MethodSignature; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.core.Ordered; |
| | | |
| | | import java.lang.reflect.Method; |
| | | |
| | | /** |
| | | * 多数据源切换的aop |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年3月5日 上午10:22:16 |
| | | */ |
| | | @Aspect |
| | | public class MultiSourceExAop implements Ordered { |
| | | |
| | | private Logger log = LoggerFactory.getLogger(this.getClass()); |
| | | |
| | | @Autowired |
| | | MutiDataSourceProperties mutiDataSourceProperties; |
| | | |
| | | @Pointcut(value = "@annotation(com.stylefeng.guns.core.mutidatasource.annotion.DataSource)") |
| | | private void cut() { |
| | | |
| | | } |
| | | |
| | | @Around("cut()") |
| | | public Object around(ProceedingJoinPoint point) throws Throwable { |
| | | |
| | | Signature signature = point.getSignature(); |
| | | MethodSignature methodSignature = null; |
| | | if (!(signature instanceof MethodSignature)) { |
| | | throw new IllegalArgumentException("该注解只能用于方法"); |
| | | } |
| | | methodSignature = (MethodSignature) signature; |
| | | |
| | | Object target = point.getTarget(); |
| | | Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes()); |
| | | |
| | | DataSource datasource = currentMethod.getAnnotation(DataSource.class); |
| | | if (datasource != null) { |
| | | DataSourceContextHolder.setDataSourceType(datasource.name()); |
| | | log.debug("设置数据源为:" + datasource.name()); |
| | | } else { |
| | | DataSourceContextHolder.setDataSourceType(mutiDataSourceProperties.getDataSourceNames()[0]); |
| | | log.debug("设置数据源为:dataSourceCurrent"); |
| | | } |
| | | |
| | | try { |
| | | return point.proceed(); |
| | | } finally { |
| | | log.debug("清空数据源信息!"); |
| | | DataSourceContextHolder.clearDataSourceType(); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * aop的顺序要早于spring的事务 |
| | | */ |
| | | @Override |
| | | public int getOrder() { |
| | | return 1; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.node; |
| | | |
| | | import com.stylefeng.guns.core.constant.IsMenu; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * @author fengshuonan |
| | | * @Description 菜单的节点 |
| | | * @date 2016年12月6日 上午11:34:17 |
| | | */ |
| | | public class MenuNode implements Comparable { |
| | | |
| | | /** |
| | | * 节点id |
| | | */ |
| | | private Long id; |
| | | |
| | | /** |
| | | * 父节点 |
| | | */ |
| | | private Long parentId; |
| | | |
| | | /** |
| | | * 节点名称 |
| | | */ |
| | | private String name; |
| | | |
| | | /** |
| | | * 按钮级别 |
| | | */ |
| | | private Integer levels; |
| | | |
| | | /** |
| | | * 按钮级别 |
| | | */ |
| | | private Integer ismenu; |
| | | |
| | | /** |
| | | * 按钮的排序 |
| | | */ |
| | | private Integer num; |
| | | |
| | | /** |
| | | * 节点的url |
| | | */ |
| | | private String url; |
| | | |
| | | /** |
| | | * 节点图标 |
| | | */ |
| | | private String icon; |
| | | |
| | | /** |
| | | * 子节点的集合 |
| | | */ |
| | | private List<MenuNode> children; |
| | | |
| | | /** |
| | | * 查询子节点时候的临时集合 |
| | | */ |
| | | private List<MenuNode> linkedList = new ArrayList<MenuNode>(); |
| | | |
| | | public MenuNode() { |
| | | super(); |
| | | } |
| | | |
| | | public MenuNode(Long id, Long parentId) { |
| | | super(); |
| | | this.id = id; |
| | | this.parentId = parentId; |
| | | } |
| | | |
| | | public Integer getLevels() { |
| | | return levels; |
| | | } |
| | | |
| | | public void setLevels(Integer levels) { |
| | | this.levels = levels; |
| | | } |
| | | |
| | | public String getIcon() { |
| | | return icon; |
| | | } |
| | | |
| | | public void setIcon(String icon) { |
| | | this.icon = icon; |
| | | } |
| | | |
| | | public static MenuNode createRoot() { |
| | | return new MenuNode(0L, -1L); |
| | | } |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public Long getParentId() { |
| | | return parentId; |
| | | } |
| | | |
| | | public void setParentId(Long parentId) { |
| | | this.parentId = parentId; |
| | | } |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public List<MenuNode> getChildren() { |
| | | return children; |
| | | } |
| | | |
| | | public void setChildren(List<MenuNode> children) { |
| | | this.children = children; |
| | | } |
| | | |
| | | public Integer getNum() { |
| | | return num; |
| | | } |
| | | |
| | | public void setNum(Integer num) { |
| | | this.num = num; |
| | | } |
| | | |
| | | public Integer getIsmenu() { |
| | | return ismenu; |
| | | } |
| | | |
| | | public void setIsmenu(Integer ismenu) { |
| | | this.ismenu = ismenu; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "MenuNode{" + |
| | | "id=" + id + |
| | | ", parentId=" + parentId + |
| | | ", name='" + name + '\'' + |
| | | ", levels=" + levels + |
| | | ", num=" + num + |
| | | ", url='" + url + '\'' + |
| | | ", icon='" + icon + '\'' + |
| | | ", children=" + children + |
| | | ", linkedList=" + linkedList + |
| | | '}'; |
| | | } |
| | | |
| | | /** |
| | | * 重写排序比较接口,首先根据等级排序,然后更具排序字段排序 |
| | | * |
| | | * @param o |
| | | * @return |
| | | */ |
| | | @Override |
| | | public int compareTo(Object o) { |
| | | MenuNode menuNode = (MenuNode) o; |
| | | Integer num = menuNode.getNum(); |
| | | Integer levels = menuNode.getLevels(); |
| | | if (num == null) { |
| | | num = 0; |
| | | } |
| | | if (levels == null) { |
| | | levels = 0; |
| | | } |
| | | if (this.levels.compareTo(levels) == 0) { |
| | | return this.num.compareTo(num); |
| | | } else { |
| | | return this.levels.compareTo(levels); |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 构建页面菜单列表 |
| | | */ |
| | | public static List<MenuNode> buildTitle(List<MenuNode> nodes) { |
| | | if (nodes.size() <= 0) { |
| | | return nodes; |
| | | } |
| | | //剔除非菜单 |
| | | nodes.removeIf(node -> node.getIsmenu() != IsMenu.YES.getCode()); |
| | | //对菜单排序,返回列表按菜单等级,序号的排序方式排列 |
| | | Collections.sort(nodes); |
| | | return mergeList(nodes, nodes.get(nodes.size() - 1).getLevels(), null); |
| | | } |
| | | |
| | | /** |
| | | * 递归合并数组为子数组,最后返回第一层 |
| | | * |
| | | * @param menuList |
| | | * @param listMap |
| | | * @return |
| | | */ |
| | | private static List<MenuNode> mergeList(List<MenuNode> menuList, int rank, Map<Long, List<MenuNode>> listMap) { |
| | | //保存当次调用总共合并了多少元素 |
| | | int n; |
| | | //保存当次调用总共合并出来的list |
| | | Map<Long, List<MenuNode>> currentMap = new HashMap<>(); |
| | | //由于按等级从小到大排序,需要从后往前排序 |
| | | //判断该节点是否属于当前循环的等级,不等于则跳出循环 |
| | | for (n = menuList.size() - 1; n >=0&&menuList.get(n).getLevels() == rank; n--) { |
| | | //判断之前的调用是否有返回以该节点的id为key的map,有则设置为children列表。 |
| | | if (listMap != null && listMap.get(menuList.get(n).getId()) != null) { |
| | | menuList.get(n).setChildren(listMap.get(menuList.get(n).getId())); |
| | | } |
| | | if (menuList.get(n).getParentId()!=null&&menuList.get(n).getParentId()!=0) { |
| | | //判断当前节点所属的pid是否已经创建了以该pid为key的键值对,没有则创建新的链表 |
| | | currentMap.computeIfAbsent(menuList.get(n).getParentId(), k -> new LinkedList<>()); |
| | | //将该节点插入到对应的list的头部 |
| | | currentMap.get(menuList.get(n).getParentId()).add(0, menuList.get(n)); |
| | | } |
| | | } |
| | | if (n <0) { |
| | | return menuList; |
| | | } else { |
| | | return mergeList(menuList.subList(0, n+1), menuList.get(n).getLevels(), currentMap); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.node; |
| | | |
| | | /** |
| | | * |
| | | * jquery ztree 插件的节点 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月17日 下午8:25:14 |
| | | */ |
| | | public class ZTreeNode { |
| | | |
| | | private Long id; //节点id |
| | | |
| | | private Long pId;//父节点id |
| | | |
| | | private String name;//节点名称 |
| | | |
| | | private Boolean open;//是否打开节点 |
| | | |
| | | private Boolean checked;//是否被选中 |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public Long getpId() { |
| | | return pId; |
| | | } |
| | | |
| | | public void setpId(Long pId) { |
| | | this.pId = pId; |
| | | } |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public Boolean getOpen() { |
| | | return open; |
| | | } |
| | | |
| | | public void setOpen(Boolean open) { |
| | | this.open = open; |
| | | } |
| | | |
| | | public Boolean getIsOpen() { |
| | | return open; |
| | | } |
| | | |
| | | public void setIsOpen(Boolean open) { |
| | | this.open = open; |
| | | } |
| | | |
| | | public Boolean getChecked() { |
| | | return checked; |
| | | } |
| | | |
| | | public void setChecked(Boolean checked) { |
| | | this.checked = checked; |
| | | } |
| | | |
| | | public static ZTreeNode createParent(){ |
| | | ZTreeNode zTreeNode = new ZTreeNode(); |
| | | zTreeNode.setChecked(true); |
| | | zTreeNode.setId(0L); |
| | | zTreeNode.setName("顶级"); |
| | | zTreeNode.setOpen(true); |
| | | zTreeNode.setpId(0L); |
| | | return zTreeNode; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.page; |
| | | |
| | | /** |
| | | * 分页参数类(for BootStrap Table) |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年1月21日 下午2:21:35 |
| | | */ |
| | | public class PageBT { |
| | | |
| | | private int limit; // 每页显示个数 |
| | | |
| | | private int offset; // 查询的偏移量(查询的页数 = offset/limit + 1) |
| | | |
| | | private String order; // 排序方式 |
| | | |
| | | |
| | | public PageBT() { |
| | | super(); |
| | | } |
| | | |
| | | public PageBT(int limit, int offset) { |
| | | super(); |
| | | this.limit = limit; |
| | | this.offset = offset; |
| | | } |
| | | |
| | | public int getLimit() { |
| | | return limit; |
| | | } |
| | | |
| | | public void setLimit(int limit) { |
| | | this.limit = limit; |
| | | } |
| | | |
| | | public int getOffset() { |
| | | return offset; |
| | | } |
| | | |
| | | public void setOffset(int offset) { |
| | | this.offset = offset; |
| | | } |
| | | |
| | | public String getOrder() { |
| | | return order; |
| | | } |
| | | |
| | | public void setOrder(String order) { |
| | | this.order = order; |
| | | } |
| | | |
| | | public int getPageSize() { |
| | | return this.limit; |
| | | } |
| | | |
| | | public int getPageNumber() { |
| | | return this.offset / this.limit + 1; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "PageBT [limit=" + limit + ", offset=" + offset + ", order=" + order + "]"; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.page; |
| | | |
| | | import com.baomidou.mybatisplus.plugins.Page; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 分页结果的封装(for Bootstrap Table) |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017年1月22日 下午11:06:41 |
| | | */ |
| | | public class PageInfoBT<T> { |
| | | |
| | | // 结果集 |
| | | private List<T> rows; |
| | | |
| | | // 总数 |
| | | private long total; |
| | | |
| | | public PageInfoBT(Page<T> page) { |
| | | this.rows = page.getRecords(); |
| | | this.total = page.getTotal(); |
| | | } |
| | | |
| | | public List<T> getRows() { |
| | | return rows; |
| | | } |
| | | |
| | | public void setRows(List<T> rows) { |
| | | this.rows = rows; |
| | | } |
| | | |
| | | public long getTotal() { |
| | | return total; |
| | | } |
| | | |
| | | public void setTotal(long total) { |
| | | this.total = total; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.qr; |
| | | |
| | | import com.google.zxing.BarcodeFormat; |
| | | import com.google.zxing.EncodeHintType; |
| | | import com.google.zxing.MultiFormatWriter; |
| | | import com.google.zxing.WriterException; |
| | | import com.google.zxing.common.BitMatrix; |
| | | import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import javax.imageio.ImageIO; |
| | | import java.awt.*; |
| | | import java.awt.geom.AffineTransform; |
| | | import java.awt.image.AffineTransformOp; |
| | | import java.awt.image.BufferedImage; |
| | | import java.io.File; |
| | | import java.io.FileOutputStream; |
| | | import java.io.IOException; |
| | | import java.io.OutputStream; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 内嵌图片的二维码生成器 |
| | | * |
| | | * @author lichunxi |
| | | */ |
| | | public class ImgQrTool { |
| | | |
| | | private static Logger log = LoggerFactory.getLogger(ImgQrTool.class); |
| | | |
| | | // 镶嵌的图片宽度的一般 |
| | | private static final int IMAGE_WIDTH = 80; |
| | | private static final int IMAGE_HEIGHT = 80; |
| | | private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2; |
| | | private static final int FRAME_WIDTH = 2; |
| | | |
| | | // 二维码写码器 |
| | | private static MultiFormatWriter mutiWriter = new MultiFormatWriter(); |
| | | |
| | | /** |
| | | * 生成带图片的二维码 |
| | | * |
| | | * @param content 二维码的内容 |
| | | * @param width 宽度 |
| | | * @param height 高度 |
| | | * @param srcImagePath 被镶嵌的图片的地址 |
| | | * @param destImagePath 生成二维码图片的地址 |
| | | * @author fengshuonan |
| | | * @since 2.3.0 |
| | | */ |
| | | public static void encode(String content, int width, int height, String srcImagePath, String destImagePath) { |
| | | try { |
| | | ImageIO.write(genBarcode(content, width, height, srcImagePath), "jpg", new File(destImagePath)); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } catch (WriterException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 生成带图片的二维码 |
| | | * |
| | | * @param content 二维码的内容 |
| | | * @param width 宽度 |
| | | * @param height 高度 |
| | | * @param srcImagePath 被镶嵌的图片的地址 |
| | | * @author fengshuonan |
| | | * @since 2.3.0 |
| | | */ |
| | | public static void encode(String content, int width, int height, String srcImagePath, OutputStream outputStream) { |
| | | try { |
| | | ImageIO.write(genBarcode(content, width, height, srcImagePath), "jpg", outputStream); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } catch (WriterException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 创建不带参数的二维码 |
| | | * |
| | | * @author fengshuonan |
| | | * @since 2.3.0 |
| | | */ |
| | | public static void createSimpleQr(String content, int width, int height, String destImagePath) { |
| | | |
| | | FileOutputStream output = null; |
| | | |
| | | try { |
| | | String format = "jpg";// 图像类型 |
| | | Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); |
| | | hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); |
| | | BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵 |
| | | File dest = new File(destImagePath); |
| | | output = new FileOutputStream(dest); |
| | | MatrixToImageWriter.writeToStream(bitMatrix, format, output);// 输出图像 |
| | | } catch (Exception e) { |
| | | log.error("生成二维码出错!ImgQrTool:createSimpleQr()", e); |
| | | } finally { |
| | | try { |
| | | output.close(); |
| | | } catch (IOException e) { |
| | | log.error("生成二维码出错!ImgQrTool:createSimpleQr()", e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static BufferedImage genBarcode(String content, int width, int height, String srcImagePath) |
| | | throws WriterException, IOException { |
| | | // 读取源图像 |
| | | BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH, IMAGE_HEIGHT, true); |
| | | int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; |
| | | for (int i = 0; i < scaleImage.getWidth(); i++) { |
| | | for (int j = 0; j < scaleImage.getHeight(); j++) { |
| | | srcPixels[i][j] = scaleImage.getRGB(i, j); |
| | | } |
| | | } |
| | | |
| | | Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>(); |
| | | hint.put(EncodeHintType.CHARACTER_SET, "utf-8"); |
| | | hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); |
| | | hint.put(EncodeHintType.MARGIN, 1);// 二维码整体白框 |
| | | |
| | | // 生成二维码 |
| | | BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hint); |
| | | |
| | | // 二维矩阵转为一维像素数组 |
| | | int halfW = matrix.getWidth() / 2; |
| | | int halfH = matrix.getHeight() / 2; |
| | | int[] pixels = new int[width * height]; |
| | | |
| | | for (int y = 0; y < matrix.getHeight(); y++) { |
| | | for (int x = 0; x < matrix.getWidth(); x++) { |
| | | // 读取图片 |
| | | if (x > halfW - IMAGE_HALF_WIDTH && x < halfW + IMAGE_HALF_WIDTH && y > halfH - IMAGE_HALF_WIDTH |
| | | && y < halfH + IMAGE_HALF_WIDTH) { |
| | | pixels[y * width + x] = srcPixels[x - halfW + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH]; |
| | | } |
| | | // 在图片四周形成边框 |
| | | else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH |
| | | && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH) |
| | | || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH |
| | | && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH |
| | | && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH) |
| | | || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH |
| | | && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH |
| | | && y < halfH - IMAGE_HALF_WIDTH + FRAME_WIDTH) |
| | | || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH |
| | | && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH |
| | | && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)) { |
| | | pixels[y * width + x] = 0xfffffff; |
| | | } else { |
| | | // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; |
| | | pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 : 0xfffffff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |
| | | image.getRaster().setDataElements(0, 0, width, height, pixels); |
| | | |
| | | return image; |
| | | } |
| | | |
| | | /** |
| | | * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标 |
| | | * |
| | | * @param srcImageFile 源文件地址 |
| | | * @param height 目标高度 |
| | | * @param width 目标宽度 |
| | | * @param hasFiller 比例不对时是否需要补白:true为补白; false为不补白; |
| | | * @throws IOException |
| | | */ |
| | | private static BufferedImage scale(String srcImageFile, int height, int width, boolean hasFiller) |
| | | throws IOException { |
| | | double ratio = 0.0; // 缩放比例 |
| | | File file = new File(srcImageFile); |
| | | BufferedImage srcImage = ImageIO.read(file); |
| | | Image destImage = srcImage.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH); |
| | | // 计算比例 |
| | | if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { |
| | | if (srcImage.getHeight() > srcImage.getWidth()) { |
| | | ratio = (new Integer(height)).doubleValue() / srcImage.getHeight(); |
| | | } else { |
| | | ratio = (new Integer(width)).doubleValue() / srcImage.getWidth(); |
| | | } |
| | | AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null); |
| | | destImage = op.filter(srcImage, null); |
| | | } |
| | | if (hasFiller) {// 补白 |
| | | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |
| | | Graphics2D graphic = image.createGraphics(); |
| | | graphic.setColor(Color.white); |
| | | graphic.fillRect(0, 0, width, height); |
| | | if (width == destImage.getWidth(null)) |
| | | graphic.drawImage(destImage, 0, (height - destImage.getHeight(null)) / 2, destImage.getWidth(null), |
| | | destImage.getHeight(null), Color.white, null); |
| | | else |
| | | graphic.drawImage(destImage, (width - destImage.getWidth(null)) / 2, 0, destImage.getWidth(null), |
| | | destImage.getHeight(null), Color.white, null); |
| | | graphic.dispose(); |
| | | destImage = image; |
| | | } |
| | | return (BufferedImage) destImage; |
| | | } |
| | | |
| | | /** |
| | | * 生成上方带文字的二维码 |
| | | */ |
| | | public static void createQrWithFontsAbove(QrImage para) { |
| | | try { |
| | | // 首先生成二维码图片 |
| | | BufferedImage qrImage = genBarcode(para.getQrContent(), para.getQrWidth(), para.getQrHeight(), para.getQrIconFilePath()); |
| | | |
| | | int qrImageWidth = qrImage.getWidth(); |
| | | int qrImageHeight = qrImage.getHeight(); |
| | | |
| | | String[] splitStrLines = null; |
| | | splitStrLines = splitStrLines(para.getWordContent(), qrImageWidth / para.getWordSize()); |
| | | int fontsImageHeight = splitStrLines.length * para.getWordSize() + 10; //防止文字遮挡 |
| | | |
| | | //创建顶部文字的图片 |
| | | BufferedImage imageWithFonts = new BufferedImage(qrImageWidth, fontsImageHeight, BufferedImage.TYPE_4BYTE_ABGR); |
| | | Graphics fontsImageGraphics = imageWithFonts.getGraphics(); |
| | | fontsImageGraphics.fillRect(0, 0, qrImageWidth, fontsImageHeight); |
| | | fontsImageGraphics.setColor(Color.black); |
| | | fontsImageGraphics.setFont(new Font("宋体", Font.PLAIN, para.getWordSize())); |
| | | |
| | | //文字长度大于一行的长度,进行分行 |
| | | if (para.getWordContent().length() > qrImageWidth / para.getWordSize()) {//每行限制的文字个数 |
| | | for (int i = 0; i < splitStrLines.length; i++) { |
| | | fontsImageGraphics.drawString(splitStrLines[i], 0, para.getWordSize() * (i + 1)); |
| | | } |
| | | } else { |
| | | fontsImageGraphics.drawString( |
| | | para.getWordContent(), |
| | | ((qrImageWidth / para.getWordSize() - para.getWordContent().length()) / 2) * para.getWordSize() + 20, //总长度减去字长度除以2为向右偏移长度 |
| | | para.getWordSize()); |
| | | } |
| | | |
| | | // 从图片中读取RGB |
| | | int[] ImageArrayFonts = new int[qrImageWidth * fontsImageHeight]; |
| | | ImageArrayFonts = imageWithFonts.getRGB(0, 0, qrImageWidth, fontsImageHeight, ImageArrayFonts, 0, qrImageWidth); |
| | | |
| | | int[] ImageArrayQr = new int[qrImageWidth * qrImageHeight]; |
| | | ImageArrayQr = qrImage.getRGB(0, 0, qrImageWidth, qrImageHeight, ImageArrayQr, 0, qrImageWidth); |
| | | |
| | | // 生成新图片 |
| | | BufferedImage ImageNew = new BufferedImage(qrImageWidth, qrImageHeight + fontsImageHeight, BufferedImage.TYPE_INT_RGB); |
| | | ImageNew.setRGB(0, 0, qrImageWidth, fontsImageHeight, ImageArrayFonts, 0, qrImageWidth);// 设置上半部分的RGB |
| | | ImageNew.setRGB(0, fontsImageHeight, qrImageWidth, qrImageHeight, ImageArrayQr, 0, qrImageWidth);// 设置下半部分的RGB |
| | | |
| | | File outFile = new File(para.getFileOutputPath()); |
| | | ImageIO.write(ImageNew, "jpg", outFile); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 一行字符串拆分成多行 |
| | | */ |
| | | private static String[] splitStrLines(String str, int len) { |
| | | int blocks = str.length() / len + 1; |
| | | String[] strs = new String[blocks]; |
| | | for (int i = 0; i < blocks; i++) { |
| | | if ((i + 1) * len > str.length()) { |
| | | strs[i] = str.substring(i * len); |
| | | } else { |
| | | strs[i] = str.substring(i * len, (i + 1) * len); |
| | | } |
| | | } |
| | | return strs; |
| | | } |
| | | |
| | | public static void main(String[] args) throws IOException { |
| | | for (int i = 1; i <= 1; i++) { |
| | | QrImage para = new QrImage.Builder() |
| | | .setFileOutputPath("D:\\二维码\\test\\" + i + ".jpg") |
| | | .setQrContent("http://www.baidu.com?a=" + "123") |
| | | .setQrHeight(300) |
| | | .setQrWidth(300) |
| | | .setQrIconFilePath("D:\\二维码\\中间图标\\1.png") |
| | | .setTopWrodHeight(100) |
| | | .setWordContent("test" + 1) |
| | | .setWordSize(18).build(); |
| | | ImgQrTool.createQrWithFontsAbove(para); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2012 ZXing authors |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | |
| | | package com.stylefeng.guns.core.qr; |
| | | |
| | | import java.awt.image.BufferedImage; |
| | | |
| | | /** |
| | | * Encapsulates custom configuration used in methods of {@link MatrixToImageWriter}. |
| | | */ |
| | | public final class MatrixToImageConfig { |
| | | |
| | | public static final int BLACK = 0xFF000000; |
| | | public static final int WHITE = 0xFFFFFFFF; |
| | | |
| | | private final int onColor; |
| | | private final int offColor; |
| | | |
| | | /** |
| | | * Creates a default config with on color {@link #BLACK} and off color {@link #WHITE}, generating normal |
| | | * black-on-white barcodes. |
| | | */ |
| | | public MatrixToImageConfig() { |
| | | this(BLACK, WHITE); |
| | | } |
| | | |
| | | /** |
| | | * @param onColor pixel on color, specified as an ARGB value as an int |
| | | * @param offColor pixel off color, specified as an ARGB value as an int |
| | | */ |
| | | public MatrixToImageConfig(int onColor, int offColor) { |
| | | this.onColor = onColor; |
| | | this.offColor = offColor; |
| | | } |
| | | |
| | | public int getPixelOnColor() { |
| | | return onColor; |
| | | } |
| | | |
| | | public int getPixelOffColor() { |
| | | return offColor; |
| | | } |
| | | |
| | | int getBufferedImageColorModel() { |
| | | // Use faster BINARY if colors match default |
| | | return onColor == BLACK && offColor == WHITE ? BufferedImage.TYPE_BYTE_BINARY : BufferedImage.TYPE_INT_RGB; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2009 ZXing authors |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.qr; |
| | | |
| | | import com.google.zxing.common.BitMatrix; |
| | | |
| | | import javax.imageio.ImageIO; |
| | | import java.awt.image.BufferedImage; |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.OutputStream; |
| | | import java.nio.file.Path; |
| | | |
| | | /** |
| | | * Writes a {@link BitMatrix} to {@link BufferedImage}, |
| | | * file or stream. Provided here instead of core since it depends on |
| | | * Java SE libraries. |
| | | * |
| | | * @author Sean Owen |
| | | */ |
| | | public final class MatrixToImageWriter { |
| | | |
| | | private static final MatrixToImageConfig DEFAULT_CONFIG = new MatrixToImageConfig(); |
| | | |
| | | private MatrixToImageWriter() {} |
| | | |
| | | /** |
| | | * Renders a {@link BitMatrix} as an image, where "false" bits are rendered |
| | | * as white, and "true" bits are rendered as black. |
| | | */ |
| | | public static BufferedImage toBufferedImage(BitMatrix matrix) { |
| | | return toBufferedImage(matrix, DEFAULT_CONFIG); |
| | | } |
| | | |
| | | /** |
| | | * As {@link #toBufferedImage(BitMatrix)}, but allows customization of the output. |
| | | */ |
| | | public static BufferedImage toBufferedImage(BitMatrix matrix, MatrixToImageConfig config) { |
| | | int width = matrix.getWidth(); |
| | | int height = matrix.getHeight(); |
| | | BufferedImage image = new BufferedImage(width, height, config.getBufferedImageColorModel()); |
| | | int onColor = config.getPixelOnColor(); |
| | | int offColor = config.getPixelOffColor(); |
| | | for (int x = 0; x < width; x++) { |
| | | for (int y = 0; y < height; y++) { |
| | | image.setRGB(x, y, matrix.get(x, y) ? onColor : offColor); |
| | | } |
| | | } |
| | | return image; |
| | | } |
| | | |
| | | /** |
| | | * @deprecated use {@link #writeToPath(BitMatrix, String, Path)} |
| | | */ |
| | | @Deprecated |
| | | public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException { |
| | | writeToPath(matrix, format, file.toPath()); |
| | | } |
| | | |
| | | /** |
| | | * Writes a {@link BitMatrix} to a file. |
| | | * |
| | | * @see #toBufferedImage(BitMatrix) |
| | | */ |
| | | public static void writeToPath(BitMatrix matrix, String format, Path file) throws IOException { |
| | | writeToPath(matrix, format, file, DEFAULT_CONFIG); |
| | | } |
| | | |
| | | /** |
| | | * @deprecated use {@link #writeToPath(BitMatrix, String, Path, MatrixToImageConfig)} |
| | | */ |
| | | @Deprecated |
| | | public static void writeToFile(BitMatrix matrix, String format, File file, MatrixToImageConfig config) |
| | | throws IOException { |
| | | writeToPath(matrix, format, file.toPath(), config); |
| | | } |
| | | |
| | | /** |
| | | * As {@link #writeToFile(BitMatrix, String, File)}, but allows customization of the output. |
| | | */ |
| | | public static void writeToPath(BitMatrix matrix, String format, Path file, MatrixToImageConfig config) |
| | | throws IOException { |
| | | BufferedImage image = toBufferedImage(matrix, config); |
| | | if (!ImageIO.write(image, format, file.toFile())) { |
| | | throw new IOException("Could not write an image of format " + format + " to " + file); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Writes a {@link BitMatrix} to a stream. |
| | | * |
| | | * @see #toBufferedImage(BitMatrix) |
| | | */ |
| | | public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException { |
| | | writeToStream(matrix, format, stream, DEFAULT_CONFIG); |
| | | } |
| | | |
| | | /** |
| | | * As {@link #writeToStream(BitMatrix, String, OutputStream)}, but allows customization of the output. |
| | | */ |
| | | public static void writeToStream(BitMatrix matrix, String format, OutputStream stream, MatrixToImageConfig config) |
| | | throws IOException { |
| | | BufferedImage image = toBufferedImage(matrix, config); |
| | | if (!ImageIO.write(image, format, stream)) { |
| | | throw new IOException("Could not write an image of format " + format); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.qr; |
| | | |
| | | /** |
| | | * 二维码图片对象 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年12月8日 上午11:37:09 |
| | | */ |
| | | public class QrImage { |
| | | |
| | | /** |
| | | * 二维码的内容 |
| | | */ |
| | | private String qrContent; |
| | | |
| | | /** |
| | | * 二维码的宽度 |
| | | */ |
| | | private int qrWidth; |
| | | |
| | | /** |
| | | * 二维码的高度 |
| | | */ |
| | | private int qrHeight; |
| | | |
| | | /** |
| | | * 二维码中间图标的文件路径 |
| | | */ |
| | | private String qrIconFilePath; |
| | | |
| | | /** |
| | | * 二维码中间小图标的边长 |
| | | */ |
| | | private int qrIconWidth; |
| | | |
| | | /** |
| | | * 顶部文字的高度 |
| | | */ |
| | | private int topWrodHeight; |
| | | |
| | | /** |
| | | * 文字的大小 |
| | | */ |
| | | private int wordSize; |
| | | |
| | | /** |
| | | * 文字的内容 |
| | | */ |
| | | private String wordContent; |
| | | |
| | | /** |
| | | * 文件的输出路径 |
| | | */ |
| | | private String fileOutputPath; |
| | | |
| | | public static class Builder { |
| | | private String qrContent; |
| | | private int qrWidth; |
| | | private int qrHeight; |
| | | private String qrIconFilePath; |
| | | private int topWrodHeight; |
| | | private int wordSize; |
| | | private String wordContent; |
| | | private String fileOutputPath; |
| | | private int qrIconWidth; |
| | | |
| | | public Builder() { |
| | | } |
| | | |
| | | public Builder setQrContent(String qrContent) { |
| | | this.qrContent = qrContent; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setQrWidth(int qrWidth) { |
| | | this.qrWidth = qrWidth; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setQrHeight(int qrHeight) { |
| | | this.qrHeight = qrHeight; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setQrIconFilePath(String qrIconFilePath) { |
| | | this.qrIconFilePath = qrIconFilePath; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTopWrodHeight(int topWrodHeight) { |
| | | this.topWrodHeight = topWrodHeight; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setWordSize(int wordSize) { |
| | | this.wordSize = wordSize; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setWordContent(String wordContent) { |
| | | this.wordContent = wordContent; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setFileOutputPath(String fileOutputPath) { |
| | | this.fileOutputPath = fileOutputPath; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setQrIconWidth(int qrIconWidth) { |
| | | this.qrIconWidth = qrIconWidth; |
| | | return this; |
| | | } |
| | | |
| | | public QrImage build() { |
| | | return new QrImage(this.qrContent, this.qrWidth, this.qrHeight, this.qrIconFilePath, this.qrIconWidth, |
| | | this.topWrodHeight, this.wordSize, this.wordContent, this.fileOutputPath); |
| | | } |
| | | } |
| | | |
| | | public QrImage(String qrContent, int qrWidth, int qrHeight, String qrIconFilePath, int qrIconWidth, |
| | | int topWrodHeight, int wordSize, String wordContent, String fileOutputPath) { |
| | | super(); |
| | | this.qrContent = qrContent; |
| | | this.qrWidth = qrWidth; |
| | | this.qrHeight = qrHeight; |
| | | this.qrIconFilePath = qrIconFilePath; |
| | | this.qrIconWidth = qrIconWidth; |
| | | this.topWrodHeight = topWrodHeight; |
| | | this.wordSize = wordSize; |
| | | this.wordContent = wordContent; |
| | | this.fileOutputPath = fileOutputPath; |
| | | } |
| | | |
| | | public String getQrContent() { |
| | | return qrContent; |
| | | } |
| | | |
| | | public int getQrWidth() { |
| | | return qrWidth; |
| | | } |
| | | |
| | | public int getQrHeight() { |
| | | return qrHeight; |
| | | } |
| | | |
| | | public String getQrIconFilePath() { |
| | | return qrIconFilePath; |
| | | } |
| | | |
| | | public int getTopWrodHeight() { |
| | | return topWrodHeight; |
| | | } |
| | | |
| | | public int getWordSize() { |
| | | return wordSize; |
| | | } |
| | | |
| | | public String getWordContent() { |
| | | return wordContent; |
| | | } |
| | | |
| | | public String getFileOutputPath() { |
| | | return fileOutputPath; |
| | | } |
| | | |
| | | public int getQrIconWidth() { |
| | | return qrIconWidth; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 基本变量类型的枚举 |
| | | * |
| | | * @author xiaoleilu |
| | | */ |
| | | public enum BasicType { |
| | | BYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING; |
| | | |
| | | /** |
| | | * 原始类型为Key,包装类型为Value,例如: int.class -> Integer.class. |
| | | */ |
| | | public static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<Class<?>, Class<?>>(8); |
| | | |
| | | /** |
| | | * 包装类型为Key,原始类型为Value,例如: Integer.class -> int.class. |
| | | */ |
| | | public static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>(8); |
| | | |
| | | static { |
| | | wrapperPrimitiveMap.put(Boolean.class, boolean.class); |
| | | wrapperPrimitiveMap.put(Byte.class, byte.class); |
| | | wrapperPrimitiveMap.put(Character.class, char.class); |
| | | wrapperPrimitiveMap.put(Double.class, double.class); |
| | | wrapperPrimitiveMap.put(Float.class, float.class); |
| | | wrapperPrimitiveMap.put(Integer.class, int.class); |
| | | wrapperPrimitiveMap.put(Long.class, long.class); |
| | | wrapperPrimitiveMap.put(Short.class, short.class); |
| | | |
| | | for (Map.Entry<Class<?>, Class<?>> entry : wrapperPrimitiveMap.entrySet()) { |
| | | primitiveWrapperMap.put(entry.getValue(), entry.getKey()); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | import com.stylefeng.guns.core.util.Convert; |
| | | |
| | | import java.beans.*; |
| | | import java.lang.reflect.Method; |
| | | import java.util.*; |
| | | import java.util.Map.Entry; |
| | | |
| | | /** |
| | | * Bean工具类 |
| | | * |
| | | * @author Looly |
| | | */ |
| | | public class BeanKit { |
| | | |
| | | /** |
| | | * 判断是否为Bean对象 |
| | | * |
| | | * @param clazz 待测试类 |
| | | * @return 是否为Bean对象 |
| | | */ |
| | | public static boolean isBean(Class<?> clazz) { |
| | | if (ClassKit.isNormalClass(clazz)) { |
| | | Method[] methods = clazz.getMethods(); |
| | | for (Method method : methods) { |
| | | if (method.getParameterTypes().length == 1 && method.getName().startsWith("set")) { |
| | | //检测包含标准的setXXX方法即视为标准的JavaBean |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | public static PropertyEditor findEditor(Class<?> type) { |
| | | return PropertyEditorManager.findEditor(type); |
| | | } |
| | | |
| | | /** |
| | | * 获得Bean字段描述数组 |
| | | * |
| | | * @param clazz Bean类 |
| | | * @return 字段描述数组 |
| | | * @throws IntrospectionException |
| | | */ |
| | | public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws IntrospectionException { |
| | | return Introspector.getBeanInfo(clazz).getPropertyDescriptors(); |
| | | } |
| | | |
| | | /** |
| | | * 获得字段名和字段描述Map |
| | | * |
| | | * @param clazz Bean类 |
| | | * @return 字段名和字段描述Map |
| | | * @throws IntrospectionException |
| | | */ |
| | | public static Map<String, PropertyDescriptor> getFieldNamePropertyDescriptorMap(Class<?> clazz) throws IntrospectionException { |
| | | final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz); |
| | | Map<String, PropertyDescriptor> map = new HashMap<>(); |
| | | for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { |
| | | map.put(propertyDescriptor.getName(), propertyDescriptor); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 获得Bean类属性描述 |
| | | * |
| | | * @param clazz Bean类 |
| | | * @param fieldName 字段名 |
| | | * @return PropertyDescriptor |
| | | * @throws IntrospectionException |
| | | */ |
| | | public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, final String fieldName) throws IntrospectionException { |
| | | PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz); |
| | | for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { |
| | | if (ObjectKit.equals(fieldName, propertyDescriptor.getName())) { |
| | | return propertyDescriptor; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Map转换为Bean对象 |
| | | * |
| | | * @param map Map |
| | | * @param beanClass Bean Class |
| | | * @return Bean |
| | | */ |
| | | public static <T> T mapToBean(Map<?, ?> map, Class<T> beanClass) { |
| | | return fillBeanWithMap(map, ClassKit.newInstance(beanClass)); |
| | | } |
| | | |
| | | /** |
| | | * Map转换为Bean对象<br> |
| | | * 忽略大小写 |
| | | * |
| | | * @param map Map |
| | | * @param beanClass Bean Class |
| | | * @return Bean |
| | | */ |
| | | public static <T> T mapToBeanIgnoreCase(Map<?, ?> map, Class<T> beanClass) { |
| | | return fillBeanWithMapIgnoreCase(map, ClassKit.newInstance(beanClass)); |
| | | } |
| | | |
| | | /** |
| | | * 使用Map填充Bean对象 |
| | | * |
| | | * @param map Map |
| | | * @param bean Bean |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBeanWithMap(final Map<?, ?> map, T bean) { |
| | | return fillBean(bean, new ValueProvider() { |
| | | @Override |
| | | public Object value(String name) { |
| | | return map.get(name); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 使用Map填充Bean对象,可配置将下划线转换为驼峰 |
| | | * |
| | | * @param map Map |
| | | * @param bean Bean |
| | | * @param isToCamelCase 是否将下划线模式转换为驼峰模式 |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBeanWithMap(Map<?, ?> map, T bean, boolean isToCamelCase) { |
| | | if (isToCamelCase) { |
| | | final Map<Object, Object> map2 = new HashMap<Object, Object>(); |
| | | for (Entry<?, ?> entry : map.entrySet()) { |
| | | final Object key = entry.getKey(); |
| | | if (null != key && key instanceof String) { |
| | | final String keyStr = (String) key; |
| | | map2.put(StrKit.toCamelCase(keyStr), entry.getValue()); |
| | | } else { |
| | | map2.put(key, entry.getValue()); |
| | | } |
| | | } |
| | | return fillBeanWithMap(map2, bean); |
| | | } |
| | | |
| | | return fillBeanWithMap(map, bean); |
| | | } |
| | | |
| | | /** |
| | | * 使用Map填充Bean对象,忽略大小写 |
| | | * |
| | | * @param map Map |
| | | * @param bean Bean |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBeanWithMapIgnoreCase(Map<?, ?> map, T bean) { |
| | | final Map<Object, Object> map2 = new HashMap<Object, Object>(); |
| | | for (Entry<?, ?> entry : map.entrySet()) { |
| | | final Object key = entry.getKey(); |
| | | if (key instanceof String) { |
| | | final String keyStr = (String) key; |
| | | map2.put(keyStr.toLowerCase(), entry.getValue()); |
| | | } else { |
| | | map2.put(key, entry.getValue()); |
| | | } |
| | | } |
| | | |
| | | return fillBean(bean, new ValueProvider() { |
| | | @Override |
| | | public Object value(String name) { |
| | | return map2.get(name.toLowerCase()); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * ServletRequest 参数转Bean |
| | | * |
| | | * @param request ServletRequest |
| | | * @param beanClass Bean Class |
| | | * @return Bean |
| | | */ |
| | | public static <T> T requestParamToBean(javax.servlet.ServletRequest request, Class<T> beanClass) { |
| | | return fillBeanWithRequestParam(request, ClassKit.newInstance(beanClass)); |
| | | } |
| | | |
| | | /** |
| | | * ServletRequest 参数转Bean |
| | | * |
| | | * @param request ServletRequest |
| | | * @param bean Bean |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBeanWithRequestParam(final javax.servlet.ServletRequest request, T bean) { |
| | | final String beanName = StrKit.lowerFirst(bean.getClass().getSimpleName()); |
| | | return fillBean(bean, new ValueProvider() { |
| | | @Override |
| | | public Object value(String name) { |
| | | String value = request.getParameter(name); |
| | | if (StrKit.isEmpty(value)) { |
| | | // 使用类名前缀尝试查找值 |
| | | value = request.getParameter(beanName + StrKit.DOT + name); |
| | | if (StrKit.isEmpty(value)) { |
| | | // 此处取得的值为空时跳过,包括null和"" |
| | | value = null; |
| | | } |
| | | } |
| | | return value; |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * ServletRequest 参数转Bean |
| | | * |
| | | * @param <T> |
| | | * @param beanClass Bean Class |
| | | * @param valueProvider 值提供者 |
| | | * @return Bean |
| | | */ |
| | | public static <T> T toBean(Class<T> beanClass, ValueProvider valueProvider) { |
| | | return fillBean(ClassKit.newInstance(beanClass), valueProvider); |
| | | } |
| | | |
| | | /** |
| | | * 填充Bean |
| | | * |
| | | * @param <T> |
| | | * @param bean Bean |
| | | * @param valueProvider 值提供者 |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBean(T bean, ValueProvider valueProvider) { |
| | | if (null == valueProvider) { |
| | | return bean; |
| | | } |
| | | |
| | | Class<?> beanClass = bean.getClass(); |
| | | try { |
| | | PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(beanClass); |
| | | String propertyName; |
| | | Object value; |
| | | for (PropertyDescriptor property : propertyDescriptors) { |
| | | propertyName = property.getName(); |
| | | value = valueProvider.value(propertyName); |
| | | if (null == value) { |
| | | continue; |
| | | } |
| | | try { |
| | | property.getWriteMethod().invoke(bean, Convert.parse(property.getPropertyType(), value)); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(e); |
| | | } |
| | | return bean; |
| | | } |
| | | |
| | | /** |
| | | * 对象转Map |
| | | * |
| | | * @param bean bean对象 |
| | | * @return Map |
| | | */ |
| | | public static <T> Map<String, Object> beanToMap(T bean) { |
| | | return beanToMap(bean, false); |
| | | } |
| | | |
| | | /** |
| | | * 对象转Map |
| | | * |
| | | * @param bean bean对象 |
| | | * @return Map |
| | | */ |
| | | public static <T> List<Map<String, Object>> listToMapList(List<T> bean) { |
| | | ArrayList<Map<String, Object>> maps = new ArrayList<>(); |
| | | for (T t : bean) { |
| | | maps.add(beanToMap(bean, false)); |
| | | } |
| | | return maps; |
| | | } |
| | | |
| | | /** |
| | | * 对象转Map |
| | | * |
| | | * @param bean bean对象 |
| | | * @param isToUnderlineCase 是否转换为下划线模式 |
| | | * @return Map |
| | | */ |
| | | public static <T> Map<String, Object> beanToMap(T bean, boolean isToUnderlineCase) { |
| | | |
| | | if (bean == null) { |
| | | return null; |
| | | } |
| | | Map<String, Object> map = new HashMap<String, Object>(); |
| | | try { |
| | | final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(bean.getClass()); |
| | | for (PropertyDescriptor property : propertyDescriptors) { |
| | | String key = property.getName(); |
| | | // 过滤class属性 |
| | | if (false == key.equals("class")) { |
| | | // 得到property对应的getter方法 |
| | | Method getter = property.getReadMethod(); |
| | | Object value = getter.invoke(bean); |
| | | if (null != value) { |
| | | map.put(isToUnderlineCase ? StrKit.toUnderlineCase(key) : key, value); |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(e); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 复制Bean对象属性 |
| | | * |
| | | * @param source 源Bean对象 |
| | | * @param target 目标Bean对象 |
| | | */ |
| | | public static void copyProperties(Object source, Object target) { |
| | | copyProperties(source, target, CopyOptions.create()); |
| | | } |
| | | |
| | | /** |
| | | * 复制Bean对象属性<br> |
| | | * 限制类用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 |
| | | * |
| | | * @param source 源Bean对象 |
| | | * @param target 目标Bean对象 |
| | | * @param ignoreProperties 不拷贝的的属性列表 |
| | | */ |
| | | public static void copyProperties(Object source, Object target, String... ignoreProperties) { |
| | | copyProperties(source, target, CopyOptions.create().setIgnoreProperties(ignoreProperties)); |
| | | } |
| | | |
| | | /** |
| | | * 复制Bean对象属性<br> |
| | | * 限制类用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 |
| | | * |
| | | * @param source 源Bean对象 |
| | | * @param target 目标Bean对象 |
| | | * @param copyOptions 拷贝选项,见 {@link CopyOptions} |
| | | */ |
| | | public static void copyProperties(Object source, Object target, CopyOptions copyOptions) { |
| | | if (null == copyOptions) { |
| | | copyOptions = new CopyOptions(); |
| | | } |
| | | |
| | | Class<?> actualEditable = target.getClass(); |
| | | if (copyOptions.editable != null) { |
| | | //检查限制类是否为target的父类或接口 |
| | | if (!copyOptions.editable.isInstance(target)) { |
| | | throw new IllegalArgumentException(StrKit.format("Target class [{}] not assignable to Editable class [{}]", target.getClass().getName(), copyOptions.editable.getName())); |
| | | } |
| | | actualEditable = copyOptions.editable; |
| | | } |
| | | PropertyDescriptor[] targetPds = null; |
| | | Map<String, PropertyDescriptor> sourcePdMap; |
| | | try { |
| | | sourcePdMap = getFieldNamePropertyDescriptorMap(source.getClass()); |
| | | targetPds = getPropertyDescriptors(actualEditable); |
| | | } catch (IntrospectionException e) { |
| | | throw new ToolBoxException(e); |
| | | } |
| | | |
| | | HashSet<String> ignoreSet = copyOptions.ignoreProperties != null ? CollectionKit.newHashSet(copyOptions.ignoreProperties) : null; |
| | | for (PropertyDescriptor targetPd : targetPds) { |
| | | Method writeMethod = targetPd.getWriteMethod(); |
| | | if (writeMethod != null && (ignoreSet == null || false == ignoreSet.contains(targetPd.getName()))) { |
| | | PropertyDescriptor sourcePd = sourcePdMap.get(targetPd.getName()); |
| | | if (sourcePd != null) { |
| | | Method readMethod = sourcePd.getReadMethod(); |
| | | // 源对象字段的getter方法返回值必须可转换为目标对象setter方法的第一个参数 |
| | | if (readMethod != null && ClassKit.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { |
| | | try { |
| | | Object value = ClassKit.setAccessible(readMethod).invoke(source); |
| | | if (null != value || false == copyOptions.isIgnoreNullValue) { |
| | | ClassKit.setAccessible(writeMethod).invoke(target, value); |
| | | } |
| | | } catch (Throwable ex) { |
| | | throw new ToolBoxException(ex, "Copy property [{}] to [{}] error: {}", sourcePd.getName(), targetPd.getName(), ex.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 值提供者,用于提供Bean注入时参数对应值得抽象接口<br> |
| | | * 继承或匿名实例化此接口<br> |
| | | * 在Bean注入过程中,Bean获得字段名,通过外部方式根据这个字段名查找相应的字段值,然后注入Bean<br> |
| | | * |
| | | * @author Looly |
| | | */ |
| | | public static interface ValueProvider { |
| | | /** |
| | | * 获取值 |
| | | * |
| | | * @param name Bean对象中参数名 |
| | | * @return 对应参数名的值 |
| | | */ |
| | | public Object value(String name); |
| | | } |
| | | |
| | | /** |
| | | * 属性拷贝选项<br> |
| | | * 包括:<br> |
| | | * 1、限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类<br> |
| | | * 2、是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null<br> |
| | | * 3、忽略的属性列表,设置一个属性列表,不拷贝这些属性值<br> |
| | | * |
| | | * @author Looly |
| | | */ |
| | | public static class CopyOptions { |
| | | /** |
| | | * 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 |
| | | */ |
| | | private Class<?> editable; |
| | | /** |
| | | * 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | */ |
| | | private boolean isIgnoreNullValue; |
| | | /** |
| | | * 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | */ |
| | | private String[] ignoreProperties; |
| | | |
| | | /** |
| | | * 创建拷贝选项 |
| | | * |
| | | * @return 拷贝选项 |
| | | */ |
| | | public static CopyOptions create() { |
| | | return new CopyOptions(); |
| | | } |
| | | |
| | | /** |
| | | * 创建拷贝选项 |
| | | * |
| | | * @param editable 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性 |
| | | * @param isIgnoreNullValue 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | * @param ignoreProperties 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | * @return 拷贝选项 |
| | | */ |
| | | public static CopyOptions create(Class<?> editable, boolean isIgnoreNullValue, String... ignoreProperties) { |
| | | return new CopyOptions(editable, isIgnoreNullValue, ignoreProperties); |
| | | } |
| | | |
| | | /** |
| | | * 构造拷贝选项 |
| | | */ |
| | | public CopyOptions() { |
| | | } |
| | | |
| | | /** |
| | | * 构造拷贝选项 |
| | | * |
| | | * @param editable 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性 |
| | | * @param isIgnoreNullValue 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | * @param ignoreProperties 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | */ |
| | | public CopyOptions(Class<?> editable, boolean isIgnoreNullValue, String... ignoreProperties) { |
| | | this.editable = editable; |
| | | this.isIgnoreNullValue = isIgnoreNullValue; |
| | | this.ignoreProperties = ignoreProperties; |
| | | } |
| | | |
| | | /** |
| | | * 设置限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性 |
| | | * |
| | | * @param editable 限制的类或接口 |
| | | * @return CopyOptions |
| | | */ |
| | | public CopyOptions setEditable(Class<?> editable) { |
| | | this.editable = editable; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | * |
| | | * @param isIgnoreNullVall 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | * @return CopyOptions |
| | | */ |
| | | public CopyOptions setIgnoreNullValue(boolean isIgnoreNullVall) { |
| | | this.isIgnoreNullValue = isIgnoreNullVall; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | * |
| | | * @param ignoreProperties 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | * @return CopyOptions |
| | | */ |
| | | public CopyOptions setIgnoreProperties(String... ignoreProperties) { |
| | | this.ignoreProperties = ignoreProperties; |
| | | return this; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | |
| | | import java.lang.reflect.Method; |
| | | import java.lang.reflect.Modifier; |
| | | |
| | | /** |
| | | * 类工具类 |
| | | * 1、扫描指定包下的所有类<br> |
| | | * 参考 http://www.oschina.net/code/snippet_234657_22722 |
| | | * @author seaside_hi, xiaoleilu, chill |
| | | * |
| | | */ |
| | | public class ClassKit { |
| | | |
| | | private ClassKit() { |
| | | // 静态类不可实例化 |
| | | } |
| | | |
| | | /** |
| | | * 是否为标准的类<br> |
| | | * 这个类必须:<br> |
| | | * 1、非接口 2、非抽象类 3、非Enum枚举 4、非数组 5、非注解 6、非原始类型(int, long等) |
| | | * |
| | | * @param clazz 类 |
| | | * @return 是否为标准类 |
| | | */ |
| | | public static boolean isNormalClass(Class<?> clazz) { |
| | | return null != clazz && false == clazz.isInterface() && false == isAbstract(clazz) && false == clazz.isEnum() && false == clazz.isArray() && false == clazz.isAnnotation() && false == clazz |
| | | .isSynthetic() && false == clazz.isPrimitive(); |
| | | } |
| | | |
| | | /** |
| | | * 是否为抽象类 |
| | | * |
| | | * @param clazz 类 |
| | | * @return 是否为抽象类 |
| | | */ |
| | | public static boolean isAbstract(Class<?> clazz) { |
| | | return Modifier.isAbstract(clazz.getModifiers()); |
| | | } |
| | | |
| | | /** |
| | | * 实例化对象 |
| | | * |
| | | * @param clazz 类名 |
| | | * @return 对象 |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static <T> T newInstance(String clazz) { |
| | | if (null == clazz) |
| | | return null; |
| | | try { |
| | | return (T) Class.forName(clazz).newInstance(); |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Instance class [{}] error!", clazz), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 实例化对象 |
| | | * |
| | | * @param clazz 类 |
| | | * @return 对象 |
| | | */ |
| | | public static <T> T newInstance(Class<T> clazz) { |
| | | if (null == clazz) |
| | | return null; |
| | | try { |
| | | return (T) clazz.newInstance(); |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Instance class [{}] error!", clazz), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 实例化对象 |
| | | * |
| | | * @param clazz 类 |
| | | * @return 对象 |
| | | */ |
| | | public static <T> T newInstance(Class<T> clazz, Object... params) { |
| | | if (null == clazz) |
| | | return null; |
| | | if (CollectionKit.isEmpty(params)) { |
| | | return newInstance(clazz); |
| | | } |
| | | try { |
| | | return clazz.getDeclaredConstructor(getClasses(params)).newInstance(params); |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Instance class [{}] error!", clazz), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获得对象数组的类数组 |
| | | * @param objects 对象数组 |
| | | * @return 类数组 |
| | | */ |
| | | public static Class<?>[] getClasses(Object... objects){ |
| | | Class<?>[] classes = new Class<?>[objects.length]; |
| | | for (int i = 0; i < objects.length; i++) { |
| | | classes[i] = objects[i].getClass(); |
| | | } |
| | | return classes; |
| | | } |
| | | |
| | | /** |
| | | * 检查目标类是否可以从原类转化<br> |
| | | * 转化包括:<br> |
| | | * 1、原类是对象,目标类型是原类型实现的接口<br> |
| | | * 2、目标类型是原类型的父类<br> |
| | | * 3、两者是原始类型或者包装类型(相互转换) |
| | | * |
| | | * @param targetType 目标类型 |
| | | * @param sourceType 原类型 |
| | | * @return 是否可转化 |
| | | */ |
| | | public static boolean isAssignable(Class<?> targetType, Class<?> sourceType) { |
| | | if (null == targetType || null == sourceType) { |
| | | return false; |
| | | } |
| | | |
| | | // 对象类型 |
| | | if (targetType.isAssignableFrom(sourceType)) { |
| | | return true; |
| | | } |
| | | |
| | | // 基本类型 |
| | | if (targetType.isPrimitive()) { |
| | | // 原始类型 |
| | | Class<?> resolvedPrimitive = BasicType.wrapperPrimitiveMap.get(sourceType); |
| | | if (resolvedPrimitive != null && targetType.equals(resolvedPrimitive)) { |
| | | return true; |
| | | } |
| | | } else { |
| | | // 包装类型 |
| | | Class<?> resolvedWrapper = BasicType.primitiveWrapperMap.get(sourceType); |
| | | if (resolvedWrapper != null && targetType.isAssignableFrom(resolvedWrapper)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 设置方法为可访问 |
| | | * |
| | | * @param method 方法 |
| | | * @return 方法 |
| | | */ |
| | | public static Method setAccessible(Method method) { |
| | | if (null != method && ClassKit.isNotPublic(method)) { |
| | | method.setAccessible(true); |
| | | } |
| | | return method; |
| | | } |
| | | |
| | | /** |
| | | * 指定类是否为非public |
| | | * |
| | | * @param clazz 类 |
| | | * @return 是否为非public |
| | | */ |
| | | public static boolean isNotPublic(Class<?> clazz) { |
| | | return false == isPublic(clazz); |
| | | } |
| | | |
| | | /** |
| | | * 指定方法是否为非public |
| | | * |
| | | * @param method 方法 |
| | | * @return 是否为非public |
| | | */ |
| | | public static boolean isNotPublic(Method method) { |
| | | return false == isPublic(method); |
| | | } |
| | | |
| | | /** |
| | | * 指定类是否为Public |
| | | * |
| | | * @param clazz 类 |
| | | * @return 是否为public |
| | | */ |
| | | public static boolean isPublic(Class<?> clazz) { |
| | | if (null == clazz) { |
| | | throw new NullPointerException("Class to provided is null."); |
| | | } |
| | | return Modifier.isPublic(clazz.getModifiers()); |
| | | } |
| | | |
| | | /** |
| | | * 指定方法是否为Public |
| | | * |
| | | * @param method 方法 |
| | | * @return 是否为public |
| | | */ |
| | | public static boolean isPublic(Method method) { |
| | | if (null == method) { |
| | | throw new NullPointerException("Method to provided is null."); |
| | | } |
| | | return isPublic(method.getDeclaringClass()); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | |
| | | import java.lang.reflect.Array; |
| | | import java.util.*; |
| | | import java.util.Map.Entry; |
| | | |
| | | /** |
| | | * 集合相关工具类,包括数组 |
| | | * |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class CollectionKit { |
| | | |
| | | private CollectionKit() { |
| | | // 静态类不可实例化 |
| | | } |
| | | |
| | | /** |
| | | * 以 conjunction 为分隔符将集合转换为字符串 |
| | | * |
| | | * @param <T> 被处理的集合 |
| | | * @param collection 集合 |
| | | * @param conjunction 分隔符 |
| | | * @return 连接后的字符串 |
| | | */ |
| | | public static <T> String join(Iterable<T> collection, String conjunction) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | boolean isFirst = true; |
| | | for (T item : collection) { |
| | | if (isFirst) { |
| | | isFirst = false; |
| | | } else { |
| | | sb.append(conjunction); |
| | | } |
| | | sb.append(item); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 以 conjunction 为分隔符将数组转换为字符串 |
| | | * |
| | | * @param <T> 被处理的集合 |
| | | * @param array 数组 |
| | | * @param conjunction 分隔符 |
| | | * @return 连接后的字符串 |
| | | */ |
| | | public static <T> String join(T[] array, String conjunction) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | boolean isFirst = true; |
| | | for (T item : array) { |
| | | if (isFirst) { |
| | | isFirst = false; |
| | | } else { |
| | | sb.append(conjunction); |
| | | } |
| | | sb.append(item); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 将多个集合排序并显示不同的段落(分页) |
| | | * @param pageNo 页码 |
| | | * @param numPerPage 每页的条目数 |
| | | * @param comparator 比较器 |
| | | * @param colls 集合数组 |
| | | * @return 分页后的段落内容 |
| | | */ |
| | | @SafeVarargs |
| | | public static <T> List<T> sortPageAll(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) { |
| | | final List<T> result = new ArrayList<T>(); |
| | | for (Collection<T> coll : colls) { |
| | | result.addAll(coll); |
| | | } |
| | | |
| | | Collections.sort(result, comparator); |
| | | |
| | | //第一页且数目少于第一页显示的数目 |
| | | if(pageNo <=1 && result.size() <= numPerPage) { |
| | | return result; |
| | | } |
| | | |
| | | final int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage); |
| | | return result.subList(startEnd[0], startEnd[1]); |
| | | } |
| | | |
| | | /** |
| | | * 将多个集合排序并显示不同的段落(分页) |
| | | * @param pageNo 页码 |
| | | * @param numPerPage 每页的条目数 |
| | | * @param comparator 比较器 |
| | | * @param colls 集合数组 |
| | | * @return 分业后的段落内容 |
| | | */ |
| | | // @SafeVarargs |
| | | // public static <T> List<T> sortPageAll2(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) { |
| | | // BoundedPriorityQueue<T> queue = new BoundedPriorityQueue<T>(pageNo * numPerPage); |
| | | // for (Collection<T> coll : colls) { |
| | | // queue.addAll(coll); |
| | | // } |
| | | // |
| | | // //第一页且数目少于第一页显示的数目 |
| | | // if(pageNo <=1 && queue.size() <= numPerPage) { |
| | | // return queue.toList(); |
| | | // } |
| | | // |
| | | // final int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage); |
| | | // return queue.toList().subList(startEnd[0], startEnd[1]); |
| | | // } |
| | | |
| | | /** |
| | | * 将Set排序(根据Entry的值) |
| | | * |
| | | * @param set 被排序的Set |
| | | * @return 排序后的Set |
| | | */ |
| | | public static List<Entry<Long, Long>> sortEntrySetToList(Set<Entry<Long, Long>> set) { |
| | | List<Entry<Long, Long>> list = new LinkedList<Entry<Long, Long>>(set); |
| | | Collections.sort(list, new Comparator<Entry<Long, Long>>(){ |
| | | |
| | | @Override |
| | | public int compare(Entry<Long, Long> o1, Entry<Long, Long> o2) { |
| | | if (o1.getValue() > o2.getValue()){ |
| | | return 1; |
| | | } |
| | | if (o1.getValue() < o2.getValue()){ |
| | | return -1; |
| | | } |
| | | return 0; |
| | | } |
| | | }); |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * 切取部分数据 |
| | | * |
| | | * @param <T> 集合元素类型 |
| | | * @param surplusAlaDatas 原数据 |
| | | * @param partSize 每部分数据的长度 |
| | | * @return 切取出的数据或null |
| | | */ |
| | | public static <T> List<T> popPart(Stack<T> surplusAlaDatas, int partSize) { |
| | | if (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){ |
| | | return null; |
| | | } |
| | | |
| | | final List<T> currentAlaDatas = new ArrayList<T>(); |
| | | int size = surplusAlaDatas.size(); |
| | | // 切割 |
| | | if (size > partSize) { |
| | | for (int i = 0; i < partSize; i++) { |
| | | currentAlaDatas.add(surplusAlaDatas.pop()); |
| | | } |
| | | } else { |
| | | for (int i = 0; i < size; i++) { |
| | | currentAlaDatas.add(surplusAlaDatas.pop()); |
| | | } |
| | | } |
| | | return currentAlaDatas; |
| | | } |
| | | |
| | | /** |
| | | * 切取部分数据 |
| | | * |
| | | * @param <T> 集合元素类型 |
| | | * @param surplusAlaDatas 原数据 |
| | | * @param partSize 每部分数据的长度 |
| | | * @return 切取出的数据或null |
| | | */ |
| | | public static <T> List<T> popPart(Deque<T> surplusAlaDatas, int partSize) { |
| | | if (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){ |
| | | return null; |
| | | } |
| | | |
| | | final List<T> currentAlaDatas = new ArrayList<T>(); |
| | | int size = surplusAlaDatas.size(); |
| | | // 切割 |
| | | if (size > partSize) { |
| | | for (int i = 0; i < partSize; i++) { |
| | | currentAlaDatas.add(surplusAlaDatas.pop()); |
| | | } |
| | | } else { |
| | | for (int i = 0; i < size; i++) { |
| | | currentAlaDatas.add(surplusAlaDatas.pop()); |
| | | } |
| | | } |
| | | return currentAlaDatas; |
| | | } |
| | | |
| | | /** |
| | | * 新建一个HashMap |
| | | * |
| | | * @return HashMap对象 |
| | | */ |
| | | public static <T, K> HashMap<T, K> newHashMap() { |
| | | return new HashMap<T, K>(); |
| | | } |
| | | |
| | | /** |
| | | * 新建一个HashMap |
| | | * @param size 初始大小,由于默认负载因子0.75,传入的size会实际初始大小为size / 0.75 |
| | | * @return HashMap对象 |
| | | */ |
| | | public static <T, K> HashMap<T, K> newHashMap(int size) { |
| | | return new HashMap<T, K>((int)(size / 0.75)); |
| | | } |
| | | |
| | | /** |
| | | * 新建一个HashSet |
| | | * |
| | | * @return HashSet对象 |
| | | */ |
| | | public static <T> HashSet<T> newHashSet() { |
| | | return new HashSet<T>(); |
| | | } |
| | | |
| | | /** |
| | | * 新建一个HashSet |
| | | * |
| | | * @return HashSet对象 |
| | | */ |
| | | @SafeVarargs |
| | | public static <T> HashSet<T> newHashSet(T... ts) { |
| | | HashSet<T> set = new HashSet<T>(); |
| | | for (T t : ts) { |
| | | set.add(t); |
| | | } |
| | | return set; |
| | | } |
| | | |
| | | /** |
| | | * 新建一个ArrayList |
| | | * |
| | | * @return ArrayList对象 |
| | | */ |
| | | public static <T> ArrayList<T> newArrayList() { |
| | | return new ArrayList<T>(); |
| | | } |
| | | |
| | | /** |
| | | * 新建一个ArrayList |
| | | * |
| | | * @return ArrayList对象 |
| | | */ |
| | | @SafeVarargs |
| | | public static <T> ArrayList<T> newArrayList(T... values) { |
| | | return new ArrayList<T>(Arrays.asList(values)); |
| | | } |
| | | |
| | | /** |
| | | * 将新元素添加到已有数组中<br/> |
| | | * 添加新元素会生成一个新的数组,不影响原数组 |
| | | * |
| | | * @param buffer 已有数组 |
| | | * @param newElement 新元素 |
| | | * @return 新数组 |
| | | */ |
| | | public static <T> T[] append(T[] buffer, T newElement) { |
| | | T[] t = resize(buffer, buffer.length + 1, newElement.getClass()); |
| | | t[buffer.length] = newElement; |
| | | return t; |
| | | } |
| | | |
| | | /** |
| | | * 生成一个新的重新设置大小的数组 |
| | | * |
| | | * @param buffer 原数组 |
| | | * @param newSize 新的数组大小 |
| | | * @param componentType 数组元素类型 |
| | | * @return 调整后的新数组 |
| | | */ |
| | | public static <T> T[] resize(T[] buffer, int newSize, Class<?> componentType) { |
| | | T[] newArray = newArray(componentType, newSize); |
| | | System.arraycopy(buffer, 0, newArray, 0, buffer.length >= newSize ? newSize : buffer.length); |
| | | return newArray; |
| | | } |
| | | |
| | | /** |
| | | * 新建一个空数组 |
| | | * @param componentType 元素类型 |
| | | * @param newSize 大小 |
| | | * @return 空数组 |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static <T> T[] newArray(Class<?> componentType, int newSize) { |
| | | return (T[]) Array.newInstance(componentType, newSize); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个新的重新设置大小的数组<br/> |
| | | * 新数组的类型为原数组的类型 |
| | | * |
| | | * @param buffer 原数组 |
| | | * @param newSize 新的数组大小 |
| | | * @return 调整后的新数组 |
| | | */ |
| | | public static <T> T[] resize(T[] buffer, int newSize) { |
| | | return resize(buffer, newSize, buffer.getClass().getComponentType()); |
| | | } |
| | | |
| | | /** |
| | | * 将多个数组合并在一起<br> |
| | | * 忽略null的数组 |
| | | * |
| | | * @param arrays 数组集合 |
| | | * @return 合并后的数组 |
| | | */ |
| | | @SafeVarargs |
| | | public static <T> T[] addAll(T[]... arrays) { |
| | | if (arrays.length == 1) { |
| | | return arrays[0]; |
| | | } |
| | | |
| | | int length = 0; |
| | | for (T[] array : arrays) { |
| | | if(array == null) { |
| | | continue; |
| | | } |
| | | length += array.length; |
| | | } |
| | | T[] result = newArray(arrays.getClass().getComponentType().getComponentType(), length); |
| | | |
| | | length = 0; |
| | | for (T[] array : arrays) { |
| | | if(array == null) { |
| | | continue; |
| | | } |
| | | System.arraycopy(array, 0, result, length, array.length); |
| | | length += array.length; |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 克隆数组 |
| | | * @param array 被克隆的数组 |
| | | * @return 新数组 |
| | | */ |
| | | public static <T> T[] clone(T[] array) { |
| | | if (array == null) { |
| | | return null; |
| | | } |
| | | return array.clone(); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个数字列表<br> |
| | | * 自动判定正序反序 |
| | | * @param excludedEnd 结束的数字(不包含) |
| | | * @return 数字列表 |
| | | */ |
| | | public static int[] range(int excludedEnd) { |
| | | return range(0, excludedEnd, 1); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个数字列表<br> |
| | | * 自动判定正序反序 |
| | | * @param includedStart 开始的数字(包含) |
| | | * @param excludedEnd 结束的数字(不包含) |
| | | * @return 数字列表 |
| | | */ |
| | | public static int[] range(int includedStart, int excludedEnd) { |
| | | return range(includedStart, excludedEnd, 1); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个数字列表<br> |
| | | * 自动判定正序反序 |
| | | * @param includedStart 开始的数字(包含) |
| | | * @param excludedEnd 结束的数字(不包含) |
| | | * @param step 步进 |
| | | * @return 数字列表 |
| | | */ |
| | | public static int[] range(int includedStart, int excludedEnd, int step) { |
| | | if(includedStart > excludedEnd) { |
| | | int tmp = includedStart; |
| | | includedStart = excludedEnd; |
| | | excludedEnd = tmp; |
| | | } |
| | | |
| | | if(step <=0) { |
| | | step = 1; |
| | | } |
| | | |
| | | int deviation = excludedEnd - includedStart; |
| | | int length = deviation / step; |
| | | if(deviation % step != 0) { |
| | | length += 1; |
| | | } |
| | | int[] range = new int[length]; |
| | | for(int i = 0; i < length; i++) { |
| | | range[i] = includedStart; |
| | | includedStart += step; |
| | | } |
| | | return range; |
| | | } |
| | | |
| | | /** |
| | | * 截取数组的部分 |
| | | * @param list 被截取的数组 |
| | | * @param start 开始位置(包含) |
| | | * @param end 结束位置(不包含) |
| | | * @return 截取后的数组,当开始位置超过最大时,返回null |
| | | */ |
| | | public static <T> List<T> sub(List<T> list, int start, int end) { |
| | | if(list == null || list.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | if(start < 0) { |
| | | start = 0; |
| | | } |
| | | if(end < 0) { |
| | | end = 0; |
| | | } |
| | | |
| | | if(start > end) { |
| | | int tmp = start; |
| | | start = end; |
| | | end = tmp; |
| | | } |
| | | |
| | | final int size = list.size(); |
| | | if(end > size) { |
| | | if(start >= size) { |
| | | return null; |
| | | } |
| | | end = size; |
| | | } |
| | | |
| | | return list.subList(start, end); |
| | | } |
| | | |
| | | /** |
| | | * 截取集合的部分 |
| | | * @param list 被截取的数组 |
| | | * @param start 开始位置(包含) |
| | | * @param end 结束位置(不包含) |
| | | * @return 截取后的数组,当开始位置超过最大时,返回null |
| | | */ |
| | | public static <T> List<T> sub(Collection<T> list, int start, int end) { |
| | | if(list == null || list.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | return sub(new ArrayList<T>(list), start, end); |
| | | } |
| | | |
| | | /** |
| | | * 数组是否为空 |
| | | * @param array 数组 |
| | | * @return 是否为空 |
| | | */ |
| | | public static <T> boolean isEmpty(T[] array) { |
| | | return array == null || array.length == 0; |
| | | } |
| | | |
| | | /** |
| | | * 数组是否为非空 |
| | | * @param array 数组 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static <T> boolean isNotEmpty(T[] array) { |
| | | return false == isEmpty(array); |
| | | } |
| | | |
| | | /** |
| | | * 集合是否为空 |
| | | * @param collection 集合 |
| | | * @return 是否为空 |
| | | */ |
| | | public static boolean isEmpty(Collection<?> collection) { |
| | | return collection == null || collection.isEmpty(); |
| | | } |
| | | |
| | | /** |
| | | * 集合是否为非空 |
| | | * @param collection 集合 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static boolean isNotEmpty(Collection<?> collection) { |
| | | return false == isEmpty(collection); |
| | | } |
| | | |
| | | /** |
| | | * Map是否为空 |
| | | * @param map 集合 |
| | | * @return 是否为空 |
| | | */ |
| | | public static boolean isEmpty(Map<?, ?> map) { |
| | | return map == null || map.isEmpty(); |
| | | } |
| | | |
| | | /** |
| | | * Map是否为非空 |
| | | * @param map 集合 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static <T> boolean isNotEmpty(Map<?, ?> map) { |
| | | return false == isEmpty(map); |
| | | } |
| | | |
| | | /** |
| | | * 映射键值(参考Python的zip()函数)<br> |
| | | * 例如:<br> |
| | | * keys = [a,b,c,d]<br> |
| | | * values = [1,2,3,4]<br> |
| | | * 则得到的Map是 {a=1, b=2, c=3, d=4}<br> |
| | | * 如果两个数组长度不同,则只对应最短部分 |
| | | * @param keys 键列表 |
| | | * @param values 值列表 |
| | | * @return Map |
| | | */ |
| | | public static <T, K> Map<T, K> zip(T[] keys, K[] values) { |
| | | if(isEmpty(keys) || isEmpty(values)) { |
| | | return null; |
| | | } |
| | | |
| | | final int size = Math.min(keys.length, values.length); |
| | | final Map<T, K> map = new HashMap<T, K>((int)(size / 0.75)); |
| | | for(int i = 0; i < size; i++) { |
| | | map.put(keys[i], values[i]); |
| | | } |
| | | |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 映射键值(参考Python的zip()函数)<br> |
| | | * 例如:<br> |
| | | * keys = a,b,c,d<br> |
| | | * values = 1,2,3,4<br> |
| | | * delimiter = , |
| | | * 则得到的Map是 {a=1, b=2, c=3, d=4}<br> |
| | | * 如果两个数组长度不同,则只对应最短部分 |
| | | * @param keys 键列表 |
| | | * @param values 值列表 |
| | | * @return Map |
| | | */ |
| | | public static Map<String, String> zip(String keys, String values, String delimiter) { |
| | | return zip(StrKit.split(keys, delimiter), StrKit.split(values, delimiter)); |
| | | } |
| | | |
| | | /** |
| | | * 映射键值(参考Python的zip()函数)<br> |
| | | * 例如:<br> |
| | | * keys = [a,b,c,d]<br> |
| | | * values = [1,2,3,4]<br> |
| | | * 则得到的Map是 {a=1, b=2, c=3, d=4}<br> |
| | | * 如果两个数组长度不同,则只对应最短部分 |
| | | * @param keys 键列表 |
| | | * @param values 值列表 |
| | | * @return Map |
| | | */ |
| | | public static <T, K> Map<T, K> zip(Collection<T> keys, Collection<K> values) { |
| | | if(isEmpty(keys) || isEmpty(values)) { |
| | | return null; |
| | | } |
| | | |
| | | final List<T> keyList = new ArrayList<T>(keys); |
| | | final List<K> valueList = new ArrayList<K>(values); |
| | | |
| | | final int size = Math.min(keys.size(), values.size()); |
| | | final Map<T, K> map = new HashMap<T, K>((int)(size / 0.75)); |
| | | for(int i = 0; i < size; i++) { |
| | | map.put(keyList.get(i), valueList.get(i)); |
| | | } |
| | | |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 数组中是否包含元素 |
| | | * @param array 数组 |
| | | * @param value 被检查的元素 |
| | | * @return 是否包含 |
| | | */ |
| | | public static <T> boolean contains(T[] array, T value) { |
| | | final Class<?> componetType = array.getClass().getComponentType(); |
| | | boolean isPrimitive = false; |
| | | if(null != componetType) { |
| | | isPrimitive = componetType.isPrimitive(); |
| | | } |
| | | for (T t : array) { |
| | | if(t == value) { |
| | | return true; |
| | | }else if(false == isPrimitive && null != value && value.equals(t)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 将Entry集合转换为HashMap |
| | | * @param entryCollection entry集合 |
| | | * @return Map |
| | | */ |
| | | public static <T, K> HashMap<T, K> toMap(Collection<Entry<T, K>> entryCollection) { |
| | | HashMap<T,K> map = new HashMap<T, K>(); |
| | | for (Entry<T, K> entry : entryCollection) { |
| | | map.put(entry.getKey(), entry.getValue()); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 将集合转换为排序后的TreeSet |
| | | * @param collection 集合 |
| | | * @param comparator 比较器 |
| | | * @return treeSet |
| | | */ |
| | | public static <T> TreeSet<T> toTreeSet(Collection<T> collection, Comparator<T> comparator){ |
| | | final TreeSet<T> treeSet = new TreeSet<T>(comparator); |
| | | for (T t : collection) { |
| | | treeSet.add(t); |
| | | } |
| | | return treeSet; |
| | | } |
| | | |
| | | /** |
| | | * 排序集合 |
| | | * @param collection 集合 |
| | | * @param comparator 比较器 |
| | | * @return treeSet |
| | | */ |
| | | public static <T> List<T> sort(Collection<T> collection, Comparator<T> comparator){ |
| | | List<T> list = new ArrayList<T>(collection); |
| | | Collections.sort(list, comparator); |
| | | return list; |
| | | } |
| | | |
| | | //------------------------------------------------------------------- 基本类型的数组转换为包装类型数组 |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Integer[] wrap(int... values){ |
| | | final int length = values.length; |
| | | Integer[] array = new Integer[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Long[] wrap(long... values){ |
| | | final int length = values.length; |
| | | Long[] array = new Long[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Character[] wrap(char... values){ |
| | | final int length = values.length; |
| | | Character[] array = new Character[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Byte[] wrap(byte... values){ |
| | | final int length = values.length; |
| | | Byte[] array = new Byte[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Short[] wrap(short... values){ |
| | | final int length = values.length; |
| | | Short[] array = new Short[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Float[] wrap(float... values){ |
| | | final int length = values.length; |
| | | Float[] array = new Float[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Double[] wrap(double... values){ |
| | | final int length = values.length; |
| | | Double[] array = new Double[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Boolean[] wrap(boolean... values){ |
| | | final int length = values.length; |
| | | Boolean[] array = new Boolean[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 判定给定对象是否为数组类型 |
| | | * @param obj 对象 |
| | | * @return 是否为数组类型 |
| | | */ |
| | | public static boolean isArray(Object obj){ |
| | | return obj.getClass().isArray(); |
| | | } |
| | | |
| | | /** |
| | | * 数组或集合转String |
| | | * |
| | | * @param obj 集合或数组对象 |
| | | * @return 数组字符串,与集合转字符串格式相同 |
| | | */ |
| | | public static String toString(Object obj) { |
| | | if (null == obj) { |
| | | return null; |
| | | } |
| | | if (isArray(obj)) { |
| | | try { |
| | | return Arrays.deepToString((Object[]) obj); |
| | | } catch (Exception e) { |
| | | final String className = obj.getClass().getComponentType().getName(); |
| | | switch (className) { |
| | | case "long": |
| | | return Arrays.toString((long[]) obj); |
| | | case "int": |
| | | return Arrays.toString((int[]) obj); |
| | | case "short": |
| | | return Arrays.toString((short[]) obj); |
| | | case "char": |
| | | return Arrays.toString((char[]) obj); |
| | | case "byte": |
| | | return Arrays.toString((byte[]) obj); |
| | | case "boolean": |
| | | return Arrays.toString((boolean[]) obj); |
| | | case "float": |
| | | return Arrays.toString((float[]) obj); |
| | | case "double": |
| | | return Arrays.toString((double[]) obj); |
| | | default: |
| | | throw new ToolBoxException(e); |
| | | } |
| | | } |
| | | } |
| | | return obj.toString(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * 封装java.util.Date |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class DateTime extends Date{ |
| | | private static final long serialVersionUID = -5395712593979185936L; |
| | | |
| | | /** |
| | | * 转换JDK date为 DateTime |
| | | * @param date JDK Date |
| | | * @return DateTime |
| | | */ |
| | | public static DateTime parse(Date date) { |
| | | return new DateTime(date); |
| | | } |
| | | |
| | | /** |
| | | * 当前时间 |
| | | */ |
| | | public DateTime() { |
| | | super(); |
| | | } |
| | | |
| | | /** |
| | | * 给定日期的构造 |
| | | * @param date 日期 |
| | | */ |
| | | public DateTime(Date date) { |
| | | this(date.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 给定日期毫秒数的构造 |
| | | * @param timeMillis 日期毫秒数 |
| | | */ |
| | | public DateTime(long timeMillis) { |
| | | super(timeMillis); |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return DateTimeKit.formatDateTime(this); |
| | | } |
| | | |
| | | public String toString(String format) { |
| | | return DateTimeKit.format(this, format); |
| | | } |
| | | |
| | | /** |
| | | * @return 输出精确到毫秒的标准日期形式 |
| | | */ |
| | | public String toMsStr() { |
| | | return DateTimeKit.format(this, DateTimeKit.NORM_DATETIME_MS_PATTERN); |
| | | } |
| | | |
| | | /** |
| | | * @return java.util.Date |
| | | */ |
| | | public Date toDate() { |
| | | return new Date(this.getTime()); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.Locale; |
| | | |
| | | /** |
| | | * 时间工具类 |
| | | * @author xiaoleilu |
| | | */ |
| | | public class DateTimeKit { |
| | | /** 毫秒 */ |
| | | public final static long MS = 1; |
| | | /** 每秒钟的毫秒数 */ |
| | | public final static long SECOND_MS = MS * 1000; |
| | | /** 每分钟的毫秒数 */ |
| | | public final static long MINUTE_MS = SECOND_MS * 60; |
| | | /** 每小时的毫秒数 */ |
| | | public final static long HOUR_MS = MINUTE_MS * 60; |
| | | /** 每天的毫秒数 */ |
| | | public final static long DAY_MS = HOUR_MS * 24; |
| | | |
| | | /** 标准日期格式 */ |
| | | public final static String NORM_DATE_PATTERN = "yyyy-MM-dd"; |
| | | /** 标准时间格式 */ |
| | | public final static String NORM_TIME_PATTERN = "HH:mm:ss"; |
| | | /** 标准日期时间格式,精确到分 */ |
| | | public final static String NORM_DATETIME_MINUTE_PATTERN = "yyyy-MM-dd HH:mm"; |
| | | /** 标准日期时间格式,精确到秒 */ |
| | | public final static String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; |
| | | /** 标准日期时间格式,精确到毫秒 */ |
| | | public final static String NORM_DATETIME_MS_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS"; |
| | | /** HTTP头中日期时间格式 */ |
| | | public final static String HTTP_DATETIME_PATTERN = "EEE, dd MMM yyyy HH:mm:ss z"; |
| | | |
| | | /** 标准日期(不含时间)格式化器 */ |
| | | // private final static SimpleDateFormat NORM_DATE_FORMAT = new SimpleDateFormat(NORM_DATE_PATTERN); |
| | | private static ThreadLocal<SimpleDateFormat> NORM_DATE_FORMAT = new ThreadLocal<SimpleDateFormat>(){ |
| | | synchronized protected SimpleDateFormat initialValue() { |
| | | return new SimpleDateFormat(NORM_DATE_PATTERN); |
| | | }; |
| | | }; |
| | | /** 标准时间格式化器 */ |
| | | // private final static SimpleDateFormat NORM_TIME_FORMAT = new SimpleDateFormat(NORM_TIME_PATTERN); |
| | | private static ThreadLocal<SimpleDateFormat> NORM_TIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){ |
| | | synchronized protected SimpleDateFormat initialValue() { |
| | | return new SimpleDateFormat(NORM_TIME_PATTERN); |
| | | }; |
| | | }; |
| | | /** 标准日期时间格式化器 */ |
| | | // private final static SimpleDateFormat NORM_DATETIME_FORMAT = new SimpleDateFormat(NORM_DATETIME_PATTERN); |
| | | private static ThreadLocal<SimpleDateFormat> NORM_DATETIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){ |
| | | synchronized protected SimpleDateFormat initialValue() { |
| | | return new SimpleDateFormat(NORM_DATETIME_PATTERN); |
| | | }; |
| | | }; |
| | | /** HTTP日期时间格式化器 */ |
| | | // private final static SimpleDateFormat HTTP_DATETIME_FORMAT = new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US); |
| | | private static ThreadLocal<SimpleDateFormat> HTTP_DATETIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){ |
| | | synchronized protected SimpleDateFormat initialValue() { |
| | | return new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US); |
| | | }; |
| | | }; |
| | | |
| | | /** |
| | | * 当前时间,格式 yyyy-MM-dd HH:mm:ss |
| | | * |
| | | * @return 当前时间的标准形式字符串 |
| | | */ |
| | | public static String now() { |
| | | return formatDateTime(new DateTime()); |
| | | } |
| | | |
| | | /** |
| | | * 当前时间long |
| | | * |
| | | * @param isNano 是否为高精度时间 |
| | | * @return 时间 |
| | | */ |
| | | public static long current(boolean isNano) { |
| | | return isNano ? System.nanoTime() : System.currentTimeMillis(); |
| | | } |
| | | |
| | | /** |
| | | * 当前日期,格式 yyyy-MM-dd |
| | | * |
| | | * @return 当前日期的标准形式字符串 |
| | | */ |
| | | public static String today() { |
| | | return formatDate(new DateTime()); |
| | | } |
| | | |
| | | /** |
| | | * @return 当前月份 |
| | | */ |
| | | public static int thisMonth() { |
| | | return month(date()); |
| | | } |
| | | |
| | | /** |
| | | * @return 今年 |
| | | */ |
| | | public static int thisYear() { |
| | | return year(date()); |
| | | } |
| | | |
| | | /** |
| | | * @return 当前时间 |
| | | */ |
| | | public static DateTime date() { |
| | | return new DateTime(); |
| | | } |
| | | |
| | | /** |
| | | * Long类型时间转为Date |
| | | * |
| | | * @param date Long类型Date(Unix时间戳) |
| | | * @return 时间对象 |
| | | */ |
| | | public static DateTime date(long date) { |
| | | return new DateTime(date); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Calendar对象 |
| | | * |
| | | * @param date 日期对象 |
| | | * @return Calendar对象 |
| | | */ |
| | | public static Calendar toCalendar(Date date) { |
| | | final Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(date); |
| | | return cal; |
| | | } |
| | | |
| | | /** |
| | | * 获得月份,从1月开始计数 |
| | | * |
| | | * @param date 日期 |
| | | * @return 月份 |
| | | */ |
| | | public static int month(Date date) { |
| | | return toCalendar(date).get(Calendar.MONTH) + 1; |
| | | } |
| | | |
| | | /** |
| | | * 获得年 |
| | | * |
| | | * @param date 日期 |
| | | * @return 年 |
| | | */ |
| | | public static int year(Date date) { |
| | | return toCalendar(date).get(Calendar.YEAR); |
| | | } |
| | | |
| | | /** |
| | | * 获得季节 |
| | | * |
| | | * @param date 日期 |
| | | * @return 第几个季节 |
| | | */ |
| | | public static int season(Date date) { |
| | | return toCalendar(date).get(Calendar.MONTH) / 3 + 1; |
| | | } |
| | | |
| | | /** |
| | | * 获得指定日期年份和季节<br> |
| | | * 格式:[20131]表示2013年第一季度 |
| | | * |
| | | * @param date 日期 |
| | | * @return Season ,类似于 20132 |
| | | */ |
| | | public static String yearAndSeason(Date date) { |
| | | return yearAndSeason(toCalendar(date)); |
| | | } |
| | | |
| | | /** |
| | | * 获得指定日期区间内的年份和季节<br> |
| | | * |
| | | * @param startDate 其实日期(包含) |
| | | * @param endDate 结束日期(包含) |
| | | * @return Season列表 ,元素类似于 20132 |
| | | */ |
| | | public static LinkedHashSet<String> yearAndSeasons(Date startDate, Date endDate) { |
| | | final LinkedHashSet<String> seasons = new LinkedHashSet<String>(); |
| | | if (startDate == null || endDate == null) { |
| | | return seasons; |
| | | } |
| | | |
| | | final Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(startDate); |
| | | while (true) { |
| | | // 如果开始时间超出结束时间,让结束时间为开始时间,处理完后结束循环 |
| | | if (startDate.after(endDate)) { |
| | | startDate = endDate; |
| | | } |
| | | |
| | | seasons.add(yearAndSeason(cal)); |
| | | |
| | | if (startDate.equals(endDate)) { |
| | | break; |
| | | } |
| | | |
| | | cal.add(Calendar.MONTH, 3); |
| | | startDate = cal.getTime(); |
| | | } |
| | | |
| | | return seasons; |
| | | } |
| | | |
| | | // ------------------------------------ Format start ---------------------------------------------- |
| | | /** |
| | | * 根据特定格式格式化日期 |
| | | * |
| | | * @param date 被格式化的日期 |
| | | * @param format 格式 |
| | | * @return 格式化后的字符串 |
| | | */ |
| | | public static String format(Date date, String format) { |
| | | return new SimpleDateFormat(format).format(date); |
| | | } |
| | | |
| | | /** |
| | | * 格式 yyyy-MM-dd HH:mm:ss |
| | | * |
| | | * @param date 被格式化的日期 |
| | | * @return 格式化后的日期 |
| | | */ |
| | | public static String formatDateTime(Date date) { |
| | | if(null == date){ |
| | | return null; |
| | | } |
| | | return NORM_DATETIME_FORMAT.get().format(date); |
| | | } |
| | | |
| | | /** |
| | | * 格式 yyyy-MM-dd |
| | | * |
| | | * @param date 被格式化的日期 |
| | | * @return 格式化后的字符串 |
| | | */ |
| | | public static String formatDate(Date date) { |
| | | if(null == date){ |
| | | return null; |
| | | } |
| | | return NORM_DATE_FORMAT.get().format(date); |
| | | } |
| | | |
| | | /** |
| | | * 格式化为Http的标准日期格式 |
| | | * |
| | | * @param date 被格式化的日期 |
| | | * @return HTTP标准形式日期字符串 |
| | | */ |
| | | public static String formatHttpDate(Date date) { |
| | | if(null == date){ |
| | | return null; |
| | | } |
| | | return HTTP_DATETIME_FORMAT.get().format(date); |
| | | } |
| | | // ------------------------------------ Format end ---------------------------------------------- |
| | | |
| | | // ------------------------------------ Parse start ---------------------------------------------- |
| | | |
| | | /** |
| | | * 构建DateTime对象 |
| | | * |
| | | * @param dateStr Date字符串 |
| | | * @param simpleDateFormat 格式化器 |
| | | * @return DateTime对象 |
| | | */ |
| | | public static DateTime parse(String dateStr, SimpleDateFormat simpleDateFormat) { |
| | | try { |
| | | return new DateTime(simpleDateFormat.parse(dateStr)); |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Parse [{}] with format [{}] error!", dateStr, simpleDateFormat.toPattern()), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 将特定格式的日期转换为Date对象 |
| | | * |
| | | * @param dateString 特定格式的日期 |
| | | * @param format 格式,例如yyyy-MM-dd |
| | | * @return 日期对象 |
| | | */ |
| | | public static DateTime parse(String dateString, String format) { |
| | | return parse(dateString, new SimpleDateFormat(format)); |
| | | } |
| | | |
| | | /** |
| | | * 格式yyyy-MM-dd HH:mm:ss |
| | | * |
| | | * @param dateString 标准形式的时间字符串 |
| | | * @return 日期对象 |
| | | */ |
| | | public static DateTime parseDateTime(String dateString) { |
| | | return parse(dateString, NORM_DATETIME_FORMAT.get()); |
| | | } |
| | | |
| | | /** |
| | | * 格式yyyy-MM-dd |
| | | * |
| | | * @param dateString 标准形式的日期字符串 |
| | | * @return 日期对象 |
| | | */ |
| | | public static DateTime parseDate(String dateString) { |
| | | return parse(dateString, NORM_DATE_FORMAT.get()); |
| | | } |
| | | |
| | | /** |
| | | * 格式HH:mm:ss |
| | | * |
| | | * @param timeString 标准形式的日期字符串 |
| | | * @return 日期对象 |
| | | */ |
| | | public static DateTime parseTime(String timeString) { |
| | | return parse(timeString, NORM_TIME_FORMAT.get()); |
| | | } |
| | | |
| | | /** |
| | | * 格式:<br> |
| | | * 1、yyyy-MM-dd HH:mm:ss<br> |
| | | * 2、yyyy-MM-dd<br> |
| | | * 3、HH:mm:ss<br> |
| | | * 4、yyyy-MM-dd HH:mm 5、yyyy-MM-dd HH:mm:ss.SSS |
| | | * |
| | | * @param dateStr 日期字符串 |
| | | * @return 日期 |
| | | */ |
| | | public static DateTime parse(String dateStr) { |
| | | if (null == dateStr) { |
| | | return null; |
| | | } |
| | | dateStr = dateStr.trim(); |
| | | int length = dateStr.length(); |
| | | try { |
| | | if (length == NORM_DATETIME_PATTERN.length()) { |
| | | return parseDateTime(dateStr); |
| | | } else if (length == NORM_DATE_PATTERN.length()) { |
| | | return parseDate(dateStr); |
| | | } else if (length == NORM_TIME_PATTERN.length()) { |
| | | return parseTime(dateStr); |
| | | } else if (length == NORM_DATETIME_MINUTE_PATTERN.length()) { |
| | | return parse(dateStr, NORM_DATETIME_MINUTE_PATTERN); |
| | | } else if (length >= NORM_DATETIME_MS_PATTERN.length() - 2) { |
| | | return parse(dateStr, NORM_DATETIME_MS_PATTERN); |
| | | } |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Parse [{}] with format normal error!", dateStr)); |
| | | } |
| | | |
| | | // 没有更多匹配的时间格式 |
| | | throw new ToolBoxException(StrKit.format(" [{}] format is not fit for date pattern!", dateStr)); |
| | | } |
| | | // ------------------------------------ Parse end ---------------------------------------------- |
| | | |
| | | // ------------------------------------ Offset start ---------------------------------------------- |
| | | /** |
| | | * 获取某天的开始时间 |
| | | * |
| | | * @param date 日期 |
| | | * @return 某天的开始时间 |
| | | */ |
| | | public static DateTime getBeginTimeOfDay(Date date) { |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.setTime(date); |
| | | calendar.set(Calendar.HOUR_OF_DAY, 0); |
| | | calendar.set(Calendar.MINUTE, 0); |
| | | calendar.set(Calendar.SECOND, 0); |
| | | calendar.set(Calendar.MILLISECOND, 0); |
| | | return new DateTime(calendar.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 获取某天的结束时间 |
| | | * |
| | | * @param date 日期 |
| | | * @return 某天的结束时间 |
| | | */ |
| | | public static DateTime getEndTimeOfDay(Date date) { |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.setTime(date); |
| | | calendar.set(Calendar.HOUR_OF_DAY, 23); |
| | | calendar.set(Calendar.MINUTE, 59); |
| | | calendar.set(Calendar.SECOND, 59); |
| | | calendar.set(Calendar.MILLISECOND, 999); |
| | | return new DateTime(calendar.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 昨天 |
| | | * |
| | | * @return 昨天 |
| | | */ |
| | | public static DateTime yesterday() { |
| | | return offsiteDay(new DateTime(), -1); |
| | | } |
| | | |
| | | /** |
| | | * 上周 |
| | | * |
| | | * @return 上周 |
| | | */ |
| | | public static DateTime lastWeek() { |
| | | return offsiteWeek(new DateTime(), -1); |
| | | } |
| | | |
| | | /** |
| | | * 上个月 |
| | | * |
| | | * @return 上个月 |
| | | */ |
| | | public static DateTime lastMouth() { |
| | | return offsiteMonth(new DateTime(), -1); |
| | | } |
| | | |
| | | /** |
| | | * 偏移天 |
| | | * |
| | | * @param date 日期 |
| | | * @param offsite 偏移天数,正数向未来偏移,负数向历史偏移 |
| | | * @return 偏移后的日期 |
| | | */ |
| | | public static DateTime offsiteDay(Date date, int offsite) { |
| | | return offsiteDate(date, Calendar.DAY_OF_YEAR, offsite); |
| | | } |
| | | |
| | | /** |
| | | * 偏移周 |
| | | * |
| | | * @param date 日期 |
| | | * @param offsite 偏移周数,正数向未来偏移,负数向历史偏移 |
| | | * @return 偏移后的日期 |
| | | */ |
| | | public static DateTime offsiteWeek(Date date, int offsite) { |
| | | return offsiteDate(date, Calendar.WEEK_OF_YEAR, offsite); |
| | | } |
| | | |
| | | /** |
| | | * 偏移月 |
| | | * |
| | | * @param date 日期 |
| | | * @param offsite 偏移月数,正数向未来偏移,负数向历史偏移 |
| | | * @return 偏移后的日期 |
| | | */ |
| | | public static DateTime offsiteMonth(Date date, int offsite) { |
| | | return offsiteDate(date, Calendar.MONTH, offsite); |
| | | } |
| | | |
| | | /** |
| | | * 获取指定日期偏移指定时间后的时间 |
| | | * |
| | | * @param date 基准日期 |
| | | * @param calendarField 偏移的粒度大小(小时、天、月等)使用Calendar中的常数 |
| | | * @param offsite 偏移量,正数为向后偏移,负数为向前偏移 |
| | | * @return 偏移后的日期 |
| | | */ |
| | | public static DateTime offsiteDate(Date date, int calendarField, int offsite) { |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(date); |
| | | cal.add(calendarField, offsite); |
| | | return new DateTime(cal.getTime()); |
| | | } |
| | | // ------------------------------------ Offset end ---------------------------------------------- |
| | | |
| | | /** |
| | | * 判断两个日期相差的时长<br/> |
| | | * 返回 minuend - subtrahend 的差 |
| | | * |
| | | * @param subtrahend 减数日期 |
| | | * @param minuend 被减数日期 |
| | | * @param diffField 相差的选项:相差的天、小时 |
| | | * @return 日期差 |
| | | */ |
| | | public static long diff(Date subtrahend, Date minuend, long diffField) { |
| | | long diff = minuend.getTime() - subtrahend.getTime(); |
| | | return diff / diffField; |
| | | } |
| | | |
| | | /** |
| | | * 计时,常用于记录某段代码的执行时间,单位:纳秒 |
| | | * |
| | | * @param preTime 之前记录的时间 |
| | | * @return 时间差,纳秒 |
| | | */ |
| | | public static long spendNt(long preTime) { |
| | | return System.nanoTime() - preTime; |
| | | } |
| | | |
| | | /** |
| | | * 计时,常用于记录某段代码的执行时间,单位:毫秒 |
| | | * |
| | | * @param preTime 之前记录的时间 |
| | | * @return 时间差,毫秒 |
| | | */ |
| | | public static long spendMs(long preTime) { |
| | | return System.currentTimeMillis() - preTime; |
| | | } |
| | | |
| | | /** |
| | | * 格式化成yyMMddHHmm后转换为int型 |
| | | * |
| | | * @param date 日期 |
| | | * @return int |
| | | */ |
| | | public static int toIntSecond(Date date) { |
| | | return Integer.parseInt(format(date, "yyMMddHHmm")); |
| | | } |
| | | |
| | | /** |
| | | * 计算指定指定时间区间内的周数 |
| | | * |
| | | * @param start 开始时间 |
| | | * @param end 结束时间 |
| | | * @return 周数 |
| | | */ |
| | | public static int weekCount(Date start, Date end) { |
| | | final Calendar startCalendar = Calendar.getInstance(); |
| | | startCalendar.setTime(start); |
| | | final Calendar endCalendar = Calendar.getInstance(); |
| | | endCalendar.setTime(end); |
| | | |
| | | final int startWeekofYear = startCalendar.get(Calendar.WEEK_OF_YEAR); |
| | | final int endWeekofYear = endCalendar.get(Calendar.WEEK_OF_YEAR); |
| | | |
| | | int count = endWeekofYear - startWeekofYear + 1; |
| | | |
| | | if (Calendar.SUNDAY != startCalendar.get(Calendar.DAY_OF_WEEK)) { |
| | | count--; |
| | | } |
| | | |
| | | return count; |
| | | } |
| | | |
| | | /** |
| | | * 计时器<br> |
| | | * 计算某个过程话费的时间,精确到毫秒 |
| | | * |
| | | * @return Timer |
| | | */ |
| | | public static Timer timer() { |
| | | return new Timer(); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 生日转为年龄,计算法定年龄 |
| | | * @param birthDay 生日,标准日期字符串 |
| | | * @return 年龄 |
| | | * @throws Exception |
| | | */ |
| | | public static int ageOfNow(String birthDay) { |
| | | return ageOfNow(parse(birthDay)); |
| | | } |
| | | |
| | | /** |
| | | * 生日转为年龄,计算法定年龄 |
| | | * @param birthDay 生日 |
| | | * @return 年龄 |
| | | * @throws Exception |
| | | */ |
| | | public static int ageOfNow(Date birthDay) { |
| | | return age(birthDay,date()); |
| | | } |
| | | |
| | | /** |
| | | * 计算相对于dateToCompare的年龄,长用于计算指定生日在某年的年龄 |
| | | * @param birthDay 生日 |
| | | * @param dateToCompare 需要对比的日期 |
| | | * @return 年龄 |
| | | * @throws Exception |
| | | */ |
| | | public static int age(Date birthDay, Date dateToCompare) { |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(dateToCompare); |
| | | |
| | | if (cal.before(birthDay)) { |
| | | throw new IllegalArgumentException(StrKit.format("Birthday is after date {}!", formatDate(dateToCompare))); |
| | | } |
| | | |
| | | int year = cal.get(Calendar.YEAR); |
| | | int month = cal.get(Calendar.MONTH); |
| | | int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH); |
| | | |
| | | cal.setTime(birthDay); |
| | | int age = year - cal.get(Calendar.YEAR); |
| | | |
| | | int monthBirth = cal.get(Calendar.MONTH); |
| | | if (month == monthBirth) { |
| | | int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH); |
| | | if (dayOfMonth < dayOfMonthBirth) { |
| | | //如果生日在当月,但是未达到生日当天的日期,年龄减一 |
| | | age--; |
| | | } |
| | | } else if (month < monthBirth){ |
| | | //如果当前月份未达到生日的月份,年龄计算减一 |
| | | age--; |
| | | } |
| | | |
| | | return age; |
| | | } |
| | | |
| | | /** |
| | | * 计时器<br> |
| | | * 计算某个过程话费的时间,精确到毫秒 |
| | | * |
| | | * @author Looly |
| | | * |
| | | */ |
| | | public static class Timer { |
| | | private long time; |
| | | private boolean isNano; |
| | | |
| | | public Timer() { |
| | | this(false); |
| | | } |
| | | |
| | | public Timer(boolean isNano) { |
| | | this.isNano = isNano; |
| | | start(); |
| | | } |
| | | |
| | | /** |
| | | * @return 开始计时并返回当前时间 |
| | | */ |
| | | public long start() { |
| | | time = current(isNano); |
| | | return time; |
| | | } |
| | | |
| | | /** |
| | | * @return 重新计时并返回从开始到当前的持续时间 |
| | | */ |
| | | public long durationRestart() { |
| | | long now = current(isNano); |
| | | long d = now - time; |
| | | time = now; |
| | | return d; |
| | | } |
| | | |
| | | /** |
| | | * @return 从开始到当前的持续时间 |
| | | */ |
| | | public long duration() { |
| | | return current(isNano) - time; |
| | | } |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------ Private method start |
| | | /** |
| | | * 获得指定日期年份和季节<br> |
| | | * 格式:[20131]表示2013年第一季度 |
| | | * |
| | | * @param cal 日期 |
| | | */ |
| | | private static String yearAndSeason(Calendar cal) { |
| | | return new StringBuilder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString(); |
| | | } |
| | | // ------------------------------------------------------------------------ Private method end |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.nio.charset.Charset; |
| | | |
| | | /** |
| | | * 十六进制(简写为hex或下标16)在数学中是一种逢16进1的进位制,一般用数字0到9和字母A到F表示(其中:A~F即10~15)。<br> |
| | | * 例如十进制数57,在二进制写作111001,在16进制写作39。<br> |
| | | * 像java,c这样的语言为了区分十六进制和十进制数值,会在十六进制数的前面加上 0x,比如0x20是十进制的32,而不是十进制的20<br> |
| | | * |
| | | * 参考:https://my.oschina.net/xinxingegeya/blog/287476 |
| | | * |
| | | * @author Looly |
| | | * |
| | | */ |
| | | public class HexKit { |
| | | |
| | | /** |
| | | * 用于建立十六进制字符的输出的小写字符数组 |
| | | */ |
| | | private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; |
| | | /** |
| | | * 用于建立十六进制字符的输出的大写字符数组 |
| | | */ |
| | | private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; |
| | | |
| | | //---------------------------------------------------------------------------------------------------- encode |
| | | /** |
| | | * 将字节数组转换为十六进制字符数组 |
| | | * |
| | | * @param data byte[] |
| | | * @return 十六进制char[] |
| | | */ |
| | | public static char[] encodeHex(byte[] data) { |
| | | return encodeHex(data, true); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符数组 |
| | | * |
| | | * @param str 字符串 |
| | | * @param charset 编码 |
| | | * @return 十六进制char[] |
| | | */ |
| | | public static char[] encodeHex(String str, Charset charset) { |
| | | return encodeHex(StrKit.getBytes(str, charset), true); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符数组 |
| | | * |
| | | * @param data byte[] |
| | | * @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式 |
| | | * @return 十六进制char[] |
| | | */ |
| | | public static char[] encodeHex(byte[] data, boolean toLowerCase) { |
| | | return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符串 |
| | | * |
| | | * @param data byte[] |
| | | * @return 十六进制String |
| | | */ |
| | | public static String encodeHexStr(byte[] data) { |
| | | return encodeHexStr(data, true); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符串 |
| | | * |
| | | * @param data byte[] |
| | | * @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式 |
| | | * @return 十六进制String |
| | | */ |
| | | public static String encodeHexStr(byte[] data, boolean toLowerCase) { |
| | | return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); |
| | | } |
| | | |
| | | //---------------------------------------------------------------------------------------------------- decode |
| | | /** |
| | | * 将十六进制字符数组转换为字符串 |
| | | * |
| | | * @param hexStr 十六进制String |
| | | * @param charset 编码 |
| | | * @return 字符串 |
| | | */ |
| | | public static String decodeHexStr(String hexStr, Charset charset) { |
| | | if(StrKit.isEmpty(hexStr)){ |
| | | return hexStr; |
| | | } |
| | | return decodeHexStr(hexStr.toCharArray(), charset); |
| | | } |
| | | |
| | | /** |
| | | * 将十六进制字符数组转换为字符串 |
| | | * |
| | | * @param hexData 十六进制char[] |
| | | * @param charset 编码 |
| | | * @return 字符串 |
| | | */ |
| | | public static String decodeHexStr(char[] hexData, Charset charset) { |
| | | return StrKit.str(decodeHex(hexData), charset); |
| | | } |
| | | |
| | | /** |
| | | * 将十六进制字符数组转换为字节数组 |
| | | * |
| | | * @param hexData 十六进制char[] |
| | | * @return byte[] |
| | | * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常 |
| | | */ |
| | | public static byte[] decodeHex(char[] hexData) { |
| | | |
| | | int len = hexData.length; |
| | | |
| | | if ((len & 0x01) != 0) { |
| | | throw new RuntimeException("Odd number of characters."); |
| | | } |
| | | |
| | | byte[] out = new byte[len >> 1]; |
| | | |
| | | // two characters form the hex value. |
| | | for (int i = 0, j = 0; j < len; i++) { |
| | | int f = toDigit(hexData[j], j) << 4; |
| | | j++; |
| | | f = f | toDigit(hexData[j], j); |
| | | j++; |
| | | out[i] = (byte) (f & 0xFF); |
| | | } |
| | | |
| | | return out; |
| | | } |
| | | |
| | | //---------------------------------------------------------------------------------------- Private method start |
| | | /** |
| | | * 将字节数组转换为十六进制字符串 |
| | | * |
| | | * @param data byte[] |
| | | * @param toDigits 用于控制输出的char[] |
| | | * @return 十六进制String |
| | | */ |
| | | private static String encodeHexStr(byte[] data, char[] toDigits) { |
| | | return new String(encodeHex(data, toDigits)); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符数组 |
| | | * |
| | | * @param data byte[] |
| | | * @param toDigits 用于控制输出的char[] |
| | | * @return 十六进制char[] |
| | | */ |
| | | private static char[] encodeHex(byte[] data, char[] toDigits) { |
| | | int l = data.length; |
| | | char[] out = new char[l << 1]; |
| | | // two characters form the hex value. |
| | | for (int i = 0, j = 0; i < l; i++) { |
| | | out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; |
| | | out[j++] = toDigits[0x0F & data[i]]; |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | /** |
| | | * 将十六进制字符转换成一个整数 |
| | | * |
| | | * @param ch 十六进制char |
| | | * @param index 十六进制字符在字符数组中的位置 |
| | | * @return 一个整数 |
| | | * @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常 |
| | | */ |
| | | private static int toDigit(char ch, int index) { |
| | | int digit = Character.digit(ch, 16); |
| | | if (digit == -1) { |
| | | throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index); |
| | | } |
| | | return digit; |
| | | } |
| | | //---------------------------------------------------------------------------------------- Private method end |
| | | |
| | | |
| | | |
| | | /** |
| | | * 2进制转16进制 |
| | | * @param bString 2进制字符串 |
| | | * @return |
| | | */ |
| | | public static String binary2Hex(String bString) { |
| | | if (bString == null || bString.equals("") || bString.length() % 8 != 0) |
| | | return null; |
| | | StringBuffer tmp = new StringBuffer(); |
| | | int iTmp = 0; |
| | | for (int i = 0; i < bString.length(); i += 4) { |
| | | iTmp = 0; |
| | | for (int j = 0; j < 4; j++) { |
| | | iTmp += Integer.parseInt(bString.substring(i + j, i + j + 1)) << (4 - j - 1); |
| | | } |
| | | tmp.append(Integer.toHexString(iTmp)); |
| | | } |
| | | return tmp.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 16进制转2进制 |
| | | * @param hexString |
| | | * @return |
| | | */ |
| | | public static String hex2Binary(String hexString) { |
| | | if (hexString == null || hexString.length() % 2 != 0) |
| | | return null; |
| | | String bString = "", tmp; |
| | | for (int i = 0; i < hexString.length(); i++) { |
| | | tmp = "0000" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16)); |
| | | bString += tmp.substring(tmp.length() - 4); |
| | | } |
| | | return bString; |
| | | } |
| | | |
| | | /** |
| | | * 将二进制转换成16进制 |
| | | * @param buf |
| | | * @return |
| | | */ |
| | | public static String binary2Hex(byte buf[]) { |
| | | StringBuffer sb = new StringBuffer(); |
| | | for (int i = 0; i < buf.length; i++) { |
| | | String hex = Integer.toHexString(buf[i] & 0xFF); |
| | | if (hex.length() == 1) { |
| | | hex = '0' + hex; |
| | | } |
| | | sb.append(hex.toUpperCase()); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 将16进制转换为二进制 |
| | | * @param hexStr |
| | | * @return |
| | | */ |
| | | public static byte[] hex2Byte(String hexStr) { |
| | | if (hexStr.length() < 1) |
| | | return null; |
| | | byte[] result = new byte[hexStr.length() / 2]; |
| | | for (int i = 0; i < hexStr.length() / 2; i++) { |
| | | int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); |
| | | int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); |
| | | result[i] = (byte) (high * 16 + low); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * <p> |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * <p> |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * <p> |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import org.springframework.web.context.request.RequestContextHolder; |
| | | import org.springframework.web.context.request.ServletRequestAttributes; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.BufferedReader; |
| | | import java.io.IOException; |
| | | import java.io.InputStreamReader; |
| | | import java.io.PrintWriter; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | import java.util.Enumeration; |
| | | import java.net.URLEncoder; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public class HttpKit { |
| | | |
| | | public static String getIp(){ |
| | | return HttpKit.getRequest().getRemoteHost(); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有请求的值 |
| | | */ |
| | | public static Map<String, String> getRequestParameters() { |
| | | HashMap<String, String> values = new HashMap<>(); |
| | | HttpServletRequest request = HttpKit.getRequest(); |
| | | Enumeration enums = request.getParameterNames(); |
| | | while ( enums.hasMoreElements()){ |
| | | String paramName = (String) enums.nextElement(); |
| | | String paramValue = request.getParameter(paramName); |
| | | values.put(paramName, paramValue); |
| | | } |
| | | return values; |
| | | } |
| | | |
| | | /** |
| | | * 获取 HttpServletRequest |
| | | */ |
| | | public static HttpServletResponse getResponse() { |
| | | HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取 包装防Xss Sql注入的 HttpServletRequest |
| | | * @return request |
| | | */ |
| | | public static HttpServletRequest getRequest() { |
| | | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); |
| | | return new WafRequestWrapper(request); |
| | | } |
| | | |
| | | /** |
| | | * 向指定URL发送GET方法的请求 |
| | | * |
| | | * @param url 发送请求的URL |
| | | * @param param 请求参数 |
| | | * @return URL 所代表远程资源的响应结果 |
| | | */ |
| | | public static String sendGet(String url, Map<String, String> param) { |
| | | String result = ""; |
| | | BufferedReader in = null; |
| | | try { |
| | | StringBuffer query = new StringBuffer(); |
| | | |
| | | for (Map.Entry<String, String> kv : param.entrySet()) { |
| | | query.append(URLEncoder.encode(kv.getKey(), "UTF-8") + "="); |
| | | query.append(URLEncoder.encode(kv.getValue(), "UTF-8") + "&"); |
| | | } |
| | | if (query.lastIndexOf("&") > 0) { |
| | | query.deleteCharAt(query.length() - 1); |
| | | } |
| | | |
| | | String urlNameString = url + "?" + query.toString(); |
| | | URL realUrl = new URL(urlNameString); |
| | | // 打开和URL之间的连接 |
| | | URLConnection connection = realUrl.openConnection(); |
| | | // 设置通用的请求属性 |
| | | connection.setRequestProperty("accept", "*/*"); |
| | | connection.setRequestProperty("connection", "Keep-Alive"); |
| | | connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); |
| | | // 建立实际的连接 |
| | | connection.connect(); |
| | | // 获取所有响应头字段 |
| | | Map<String, List<String>> map = connection.getHeaderFields(); |
| | | // 遍历所有的响应头字段 |
| | | for (String key : map.keySet()) { |
| | | System.out.println(key + "--->" + map.get(key)); |
| | | } |
| | | // 定义 BufferedReader输入流来读取URL的响应 |
| | | in = new BufferedReader(new InputStreamReader(connection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | result += line; |
| | | } |
| | | } catch (Exception e) { |
| | | System.out.println("发送GET请求出现异常!" + e); |
| | | e.printStackTrace(); |
| | | } |
| | | // 使用finally块来关闭输入流 |
| | | finally { |
| | | try { |
| | | if (in != null) { |
| | | in.close(); |
| | | } |
| | | } catch (Exception e2) { |
| | | e2.printStackTrace(); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 向指定 URL 发送POST方法的请求 |
| | | * |
| | | * @param url 发送请求的 URL |
| | | * @param param 请求参数 |
| | | * @return 所代表远程资源的响应结果 |
| | | */ |
| | | public static String sendPost(String url, Map<String, String> param) { |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | String result = ""; |
| | | try { |
| | | String para = ""; |
| | | for (String key : param.keySet()) { |
| | | para += (key + "=" + param.get(key) + "&"); |
| | | } |
| | | if (para.lastIndexOf("&") > 0) { |
| | | para = para.substring(0, para.length() - 1); |
| | | } |
| | | String urlNameString = url + "?" + para; |
| | | URL realUrl = new URL(urlNameString); |
| | | // 打开和URL之间的连接 |
| | | URLConnection conn = realUrl.openConnection(); |
| | | // 设置通用的请求属性 |
| | | conn.setRequestProperty("accept", "*/*"); |
| | | conn.setRequestProperty("connection", "Keep-Alive"); |
| | | conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); |
| | | // 发送POST请求必须设置如下两行 |
| | | conn.setDoOutput(true); |
| | | conn.setDoInput(true); |
| | | // 获取URLConnection对象对应的输出流 |
| | | out = new PrintWriter(conn.getOutputStream()); |
| | | // 发送请求参数 |
| | | out.print(param); |
| | | // flush输出流的缓冲 |
| | | out.flush(); |
| | | // 定义BufferedReader输入流来读取URL的响应 |
| | | in = new BufferedReader(new InputStreamReader(conn.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | result += line; |
| | | } |
| | | } catch (Exception e) { |
| | | System.out.println("发送 POST 请求出现异常!" + e); |
| | | e.printStackTrace(); |
| | | } |
| | | // 使用finally块来关闭输出流、输入流 |
| | | finally { |
| | | try { |
| | | if (out != null) { |
| | | out.close(); |
| | | } |
| | | if (in != null) { |
| | | in.close(); |
| | | } |
| | | } catch (IOException ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | /** |
| | | * 一些通用的函数 |
| | | * |
| | | * @author Looly |
| | | * |
| | | */ |
| | | public class ObjectKit { |
| | | /** |
| | | * 比较两个对象是否相等。<br> |
| | | * 相同的条件有两个,满足其一即可:<br> |
| | | * 1. obj1 == null && obj2 == null; 2. obj1.equals(obj2) |
| | | * |
| | | * @param obj1 对象1 |
| | | * @param obj2 对象2 |
| | | * @return 是否相等 |
| | | */ |
| | | public static boolean equals(Object obj1, Object obj2) { |
| | | return (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | /** |
| | | * 分页工具类 |
| | | * |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class PageKit { |
| | | |
| | | /** |
| | | * 将页数和每页条目数转换为开始位置和结束位置<br> |
| | | * 此方法用于不包括结束位置的分页方法<br> |
| | | * 例如:<br> |
| | | * 页码:1,每页10 -> [0, 10]<br> |
| | | * 页码:2,每页10 -> [10, 20]<br> |
| | | * 。。。<br> |
| | | * |
| | | * @param pageNo |
| | | * 页码(从1计数) |
| | | * @param countPerPage |
| | | * 每页条目数 |
| | | * @return 第一个数为开始位置,第二个数为结束位置 |
| | | */ |
| | | public static int[] transToStartEnd(int pageNo, int countPerPage) { |
| | | if (pageNo < 1) { |
| | | pageNo = 1; |
| | | } |
| | | |
| | | if (countPerPage < 1) { |
| | | countPerPage = 0; |
| | | // LogKit.warn("Count per page [" + countPerPage + "] is not valid!"); |
| | | } |
| | | |
| | | int start = (pageNo - 1) * countPerPage; |
| | | int end = start + countPerPage; |
| | | |
| | | return new int[] { start, end }; |
| | | } |
| | | |
| | | /** |
| | | * 根据总数计算总页数 |
| | | * |
| | | * @param totalCount |
| | | * 总数 |
| | | * @param numPerPage |
| | | * 每页数 |
| | | * @return 总页数 |
| | | */ |
| | | public static int totalPage(int totalCount, int numPerPage) { |
| | | if (numPerPage == 0) { |
| | | return 0; |
| | | } |
| | | return totalCount % numPerPage == 0 ? (totalCount / numPerPage) |
| | | : (totalCount / numPerPage + 1); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.io.StringReader; |
| | | import java.io.StringWriter; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.nio.ByteBuffer; |
| | | import java.nio.charset.Charset; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Map.Entry; |
| | | |
| | | /** |
| | | * 字符串工具类 |
| | | * |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class StrKit { |
| | | |
| | | public static final String SPACE = " "; |
| | | public static final String DOT = "."; |
| | | public static final String SLASH = "/"; |
| | | public static final String BACKSLASH = "\\"; |
| | | public static final String EMPTY = ""; |
| | | public static final String CRLF = "\r\n"; |
| | | public static final String NEWLINE = "\n"; |
| | | public static final String UNDERLINE = "_"; |
| | | public static final String COMMA = ","; |
| | | |
| | | public static final String HTML_NBSP = " "; |
| | | public static final String HTML_AMP = "&"; |
| | | public static final String HTML_QUOTE = """; |
| | | public static final String HTML_LT = "<"; |
| | | public static final String HTML_GT = ">"; |
| | | |
| | | public static final String EMPTY_JSON = "{}"; |
| | | |
| | | |
| | | /** |
| | | * 首字母变小写 |
| | | */ |
| | | public static String firstCharToLowerCase(String str) { |
| | | char firstChar = str.charAt(0); |
| | | if (firstChar >= 'A' && firstChar <= 'Z') { |
| | | char[] arr = str.toCharArray(); |
| | | arr[0] += ('a' - 'A'); |
| | | return new String(arr); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 首字母变大写 |
| | | */ |
| | | public static String firstCharToUpperCase(String str) { |
| | | char firstChar = str.charAt(0); |
| | | if (firstChar >= 'a' && firstChar <= 'z') { |
| | | char[] arr = str.toCharArray(); |
| | | arr[0] -= ('a' - 'A'); |
| | | return new String(arr); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------ Blank |
| | | /** |
| | | * 字符串是否为空白 空白的定义如下: <br> |
| | | * 1、为null <br> |
| | | * 2、为不可见字符(如空格)<br> |
| | | * 3、""<br> |
| | | * |
| | | * @param str 被检测的字符串 |
| | | * @return 是否为空 |
| | | */ |
| | | public static boolean isBlank(String str) { |
| | | int length; |
| | | if ((str == null) || ((length = str.length()) == 0)) { |
| | | return true; |
| | | } |
| | | for (int i = 0; i < length; i++) { |
| | | // 只要有一个非空字符即为非空字符串 |
| | | if (false == Character.isWhitespace(str.charAt(i))) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 字符串是否为非空白 空白的定义如下: <br> |
| | | * 1、不为null <br> |
| | | * 2、不为不可见字符(如空格)<br> |
| | | * 3、不为""<br> |
| | | * |
| | | * @param str 被检测的字符串 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static boolean notBlank(String str) { |
| | | return false == isBlank(str); |
| | | } |
| | | |
| | | /** |
| | | * 是否包含空字符串 |
| | | * |
| | | * @param strs 字符串列表 |
| | | * @return 是否包含空字符串 |
| | | */ |
| | | public static boolean hasBlank(String... strs) { |
| | | if (CollectionKit.isEmpty(strs)) { |
| | | return true; |
| | | } |
| | | for (String str : strs) { |
| | | if (isBlank(str)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 给定所有字符串是否为空白 |
| | | * |
| | | * @param strs 字符串 |
| | | * @return 所有字符串是否为空白 |
| | | */ |
| | | public static boolean isAllBlank(String... strs) { |
| | | if (CollectionKit.isEmpty(strs)) { |
| | | return true; |
| | | } |
| | | for (String str : strs) { |
| | | if (notBlank(str)) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------ Empty |
| | | /** |
| | | * 字符串是否为空,空的定义如下 1、为null <br> |
| | | * 2、为""<br> |
| | | * |
| | | * @param str 被检测的字符串 |
| | | * @return 是否为空 |
| | | */ |
| | | public static boolean isEmpty(String str) { |
| | | return str == null || str.length() == 0; |
| | | } |
| | | |
| | | /** |
| | | * 字符串是否为非空白 空白的定义如下: <br> |
| | | * 1、不为null <br> |
| | | * 2、不为""<br> |
| | | * |
| | | * @param str 被检测的字符串 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static boolean isNotEmpty(String str) { |
| | | return false == isEmpty(str); |
| | | } |
| | | |
| | | /** |
| | | * 当给定字符串为null时,转换为Empty |
| | | * |
| | | * @param str 被转换的字符串 |
| | | * @return 转换后的字符串 |
| | | */ |
| | | public static String nullToEmpty(String str) { |
| | | return nullToDefault(str, EMPTY); |
| | | } |
| | | |
| | | /** |
| | | * 如果字符串是<code>null</code>,则返回指定默认字符串,否则返回字符串本身。 |
| | | * |
| | | * <pre> |
| | | * nullToDefault(null, "default") = "default" |
| | | * nullToDefault("", "default") = "" |
| | | * nullToDefault(" ", "default") = " " |
| | | * nullToDefault("bat", "default") = "bat" |
| | | * </pre> |
| | | * |
| | | * @param str 要转换的字符串 |
| | | * @param defaultStr 默认字符串 |
| | | * |
| | | * @return 字符串本身或指定的默认字符串 |
| | | */ |
| | | public static String nullToDefault(String str, String defaultStr) { |
| | | return (str == null) ? defaultStr : str; |
| | | } |
| | | |
| | | /** |
| | | * 当给定字符串为空字符串时,转换为<code>null</code> |
| | | * |
| | | * @param str 被转换的字符串 |
| | | * @return 转换后的字符串 |
| | | */ |
| | | public static String emptyToNull(String str) { |
| | | return isEmpty(str) ? null : str; |
| | | } |
| | | |
| | | /** |
| | | * 是否包含空字符串 |
| | | * |
| | | * @param strs 字符串列表 |
| | | * @return 是否包含空字符串 |
| | | */ |
| | | public static boolean hasEmpty(String... strs) { |
| | | if (CollectionKit.isEmpty(strs)) { |
| | | return true; |
| | | } |
| | | |
| | | for (String str : strs) { |
| | | if (isEmpty(str)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 是否全部为空字符串 |
| | | * |
| | | * @param strs 字符串列表 |
| | | * @return 是否全部为空字符串 |
| | | */ |
| | | public static boolean isAllEmpty(String... strs) { |
| | | if (CollectionKit.isEmpty(strs)) { |
| | | return true; |
| | | } |
| | | |
| | | for (String str : strs) { |
| | | if (isNotEmpty(str)) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------ Trim |
| | | /** |
| | | * 除去字符串头尾部的空白,如果字符串是<code>null</code>,依然返回<code>null</code>。 |
| | | * |
| | | * <p> |
| | | * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 |
| | | * |
| | | * <pre> |
| | | * trim(null) = null |
| | | * trim("") = "" |
| | | * trim(" ") = "" |
| | | * trim("abc") = "abc" |
| | | * trim(" abc ") = "abc" |
| | | * </pre> |
| | | * |
| | | * </p> |
| | | * |
| | | * @param str 要处理的字符串 |
| | | * |
| | | * @return 除去空白的字符串,如果原字串为<code>null</code>,则返回<code>null</code> |
| | | */ |
| | | public static String trim(String str) { |
| | | return (null == str) ? null : trim(str, 0); |
| | | } |
| | | |
| | | /** |
| | | * 给定字符串数组全部做去首尾空格 |
| | | * |
| | | * @param strs 字符串数组 |
| | | */ |
| | | public static void trim(String[] strs) { |
| | | if (null == strs) { |
| | | return; |
| | | } |
| | | String str; |
| | | for (int i = 0; i < strs.length; i++) { |
| | | str = strs[i]; |
| | | if (null != str) { |
| | | strs[i] = str.trim(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 除去字符串头部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。 |
| | | * |
| | | * <p> |
| | | * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 |
| | | * |
| | | * <pre> |
| | | * trimStart(null) = null |
| | | * trimStart("") = "" |
| | | * trimStart("abc") = "abc" |
| | | * trimStart(" abc") = "abc" |
| | | * trimStart("abc ") = "abc " |
| | | * trimStart(" abc ") = "abc " |
| | | * </pre> |
| | | * |
| | | * </p> |
| | | * |
| | | * @param str 要处理的字符串 |
| | | * |
| | | * @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code> |
| | | */ |
| | | public static String trimStart(String str) { |
| | | return trim(str, -1); |
| | | } |
| | | |
| | | /** |
| | | * 除去字符串尾部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。 |
| | | * |
| | | * <p> |
| | | * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 |
| | | * |
| | | * <pre> |
| | | * trimEnd(null) = null |
| | | * trimEnd("") = "" |
| | | * trimEnd("abc") = "abc" |
| | | * trimEnd(" abc") = " abc" |
| | | * trimEnd("abc ") = "abc" |
| | | * trimEnd(" abc ") = " abc" |
| | | * </pre> |
| | | * |
| | | * </p> |
| | | * |
| | | * @param str 要处理的字符串 |
| | | * |
| | | * @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code> |
| | | */ |
| | | public static String trimEnd(String str) { |
| | | return trim(str, 1); |
| | | } |
| | | |
| | | /** |
| | | * 除去字符串头尾部的空白符,如果字符串是<code>null</code>,依然返回<code>null</code>。 |
| | | * |
| | | * @param str 要处理的字符串 |
| | | * @param mode <code>-1</code>表示trimStart,<code>0</code>表示trim全部, <code>1</code>表示trimEnd |
| | | * |
| | | * @return 除去指定字符后的的字符串,如果原字串为<code>null</code>,则返回<code>null</code> |
| | | */ |
| | | public static String trim(String str, int mode) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | |
| | | int length = str.length(); |
| | | int start = 0; |
| | | int end = length; |
| | | |
| | | // 扫描字符串头部 |
| | | if (mode <= 0) { |
| | | while ((start < end) && (Character.isWhitespace(str.charAt(start)))) { |
| | | start++; |
| | | } |
| | | } |
| | | |
| | | // 扫描字符串尾部 |
| | | if (mode >= 0) { |
| | | while ((start < end) && (Character.isWhitespace(str.charAt(end - 1)))) { |
| | | end--; |
| | | } |
| | | } |
| | | |
| | | if ((start > 0) || (end < length)) { |
| | | return str.substring(start, end); |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 是否以指定字符串开头 |
| | | * @param str 被监测字符串 |
| | | * @param prefix 开头字符串 |
| | | * @param isIgnoreCase 是否忽略大小写 |
| | | * @return 是否以指定字符串开头 |
| | | */ |
| | | public static boolean startWith(String str, String prefix, boolean isIgnoreCase){ |
| | | if(isIgnoreCase){ |
| | | return str.toLowerCase().startsWith(prefix.toLowerCase()); |
| | | }else{ |
| | | return str.startsWith(prefix); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 是否以指定字符串结尾 |
| | | * @param str 被监测字符串 |
| | | * @param suffix 结尾字符串 |
| | | * @param isIgnoreCase 是否忽略大小写 |
| | | * @return 是否以指定字符串结尾 |
| | | */ |
| | | public static boolean endWith(String str, String suffix, boolean isIgnoreCase){ |
| | | if(isIgnoreCase){ |
| | | return str.toLowerCase().endsWith(suffix.toLowerCase()); |
| | | }else{ |
| | | return str.endsWith(suffix); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 是否包含特定字符,忽略大小写,如果给定两个参数都为<code>null</code>,返回true |
| | | * @param str 被检测字符串 |
| | | * @param testStr 被测试是否包含的字符串 |
| | | * @return 是否包含 |
| | | */ |
| | | public static boolean containsIgnoreCase(String str, String testStr){ |
| | | if(null == str){ |
| | | //如果被监测字符串和 |
| | | return null == testStr; |
| | | } |
| | | return str.toLowerCase().contains(testStr.toLowerCase()); |
| | | } |
| | | |
| | | /** |
| | | * 获得set或get方法对应的标准属性名<br/> |
| | | * 例如:setName 返回 name |
| | | * |
| | | * @param getOrSetMethodName |
| | | * @return 如果是set或get方法名,返回field, 否则null |
| | | */ |
| | | public static String getGeneralField(String getOrSetMethodName) { |
| | | if (getOrSetMethodName.startsWith("get") || getOrSetMethodName.startsWith("set")) { |
| | | return cutPreAndLowerFirst(getOrSetMethodName, 3); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 生成set方法名<br/> |
| | | * 例如:name 返回 setName |
| | | * |
| | | * @param fieldName 属性名 |
| | | * @return setXxx |
| | | */ |
| | | public static String genSetter(String fieldName) { |
| | | return upperFirstAndAddPre(fieldName, "set"); |
| | | } |
| | | |
| | | /** |
| | | * 生成get方法名 |
| | | * |
| | | * @param fieldName 属性名 |
| | | * @return getXxx |
| | | */ |
| | | public static String genGetter(String fieldName) { |
| | | return upperFirstAndAddPre(fieldName, "get"); |
| | | } |
| | | |
| | | /** |
| | | * 去掉首部指定长度的字符串并将剩余字符串首字母小写<br/> |
| | | * 例如:str=setName, preLength=3 -> return name |
| | | * |
| | | * @param str 被处理的字符串 |
| | | * @param preLength 去掉的长度 |
| | | * @return 处理后的字符串,不符合规范返回null |
| | | */ |
| | | public static String cutPreAndLowerFirst(String str, int preLength) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | if (str.length() > preLength) { |
| | | char first = Character.toLowerCase(str.charAt(preLength)); |
| | | if (str.length() > preLength + 1) { |
| | | return first + str.substring(preLength + 1); |
| | | } |
| | | return String.valueOf(first); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 原字符串首字母大写并在其首部添加指定字符串 例如:str=name, preString=get -> return getName |
| | | * |
| | | * @param str 被处理的字符串 |
| | | * @param preString 添加的首部 |
| | | * @return 处理后的字符串 |
| | | */ |
| | | public static String upperFirstAndAddPre(String str, String preString) { |
| | | if (str == null || preString == null) { |
| | | return null; |
| | | } |
| | | return preString + upperFirst(str); |
| | | } |
| | | |
| | | /** |
| | | * 大写首字母<br> |
| | | * 例如:str = name, return Name |
| | | * |
| | | * @param str 字符串 |
| | | * @return 字符串 |
| | | */ |
| | | public static String upperFirst(String str) { |
| | | return Character.toUpperCase(str.charAt(0)) + str.substring(1); |
| | | } |
| | | |
| | | /** |
| | | * 小写首字母<br> |
| | | * 例如:str = Name, return name |
| | | * |
| | | * @param str 字符串 |
| | | * @return 字符串 |
| | | */ |
| | | public static String lowerFirst(String str) { |
| | | if(isBlank(str)){ |
| | | return str; |
| | | } |
| | | return Character.toLowerCase(str.charAt(0)) + str.substring(1); |
| | | } |
| | | |
| | | /** |
| | | * 去掉指定前缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @return 切掉后的字符串,若前缀不是 preffix, 返回原字符串 |
| | | */ |
| | | public static String removePrefix(String str, String prefix) { |
| | | if(isEmpty(str) || isEmpty(prefix)){ |
| | | return str; |
| | | } |
| | | |
| | | if (str.startsWith(prefix)) { |
| | | return str.substring(prefix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 忽略大小写去掉指定前缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串 |
| | | */ |
| | | public static String removePrefixIgnoreCase(String str, String prefix) { |
| | | if(isEmpty(str) || isEmpty(prefix)){ |
| | | return str; |
| | | } |
| | | |
| | | if (str.toLowerCase().startsWith(prefix.toLowerCase())) { |
| | | return str.substring(prefix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 去掉指定后缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param suffix 后缀 |
| | | * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串 |
| | | */ |
| | | public static String removeSuffix(String str, String suffix) { |
| | | if(isEmpty(str) || isEmpty(suffix)){ |
| | | return str; |
| | | } |
| | | |
| | | if (str.endsWith(suffix)) { |
| | | return str.substring(0, str.length() - suffix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 获得字符串对应byte数组 |
| | | * @param str 字符串 |
| | | * @param charset 编码,如果为<code>null</code>使用系统默认编码 |
| | | * @return bytes |
| | | */ |
| | | public static byte[] getBytes(String str, Charset charset){ |
| | | if(null == str){ |
| | | return null; |
| | | } |
| | | return null == charset ? str.getBytes() : str.getBytes(charset); |
| | | } |
| | | |
| | | /** |
| | | * 忽略大小写去掉指定后缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param suffix 后缀 |
| | | * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串 |
| | | */ |
| | | public static String removeSuffixIgnoreCase(String str, String suffix) { |
| | | if(isEmpty(str) || isEmpty(suffix)){ |
| | | return str; |
| | | } |
| | | |
| | | if (str.toLowerCase().endsWith(suffix.toLowerCase())) { |
| | | return str.substring(0, str.length() - suffix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 如果给定字符串不是以prefix开头的,在开头补充 prefix |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @return 补充后的字符串 |
| | | */ |
| | | public static String addPrefixIfNot(String str, String prefix){ |
| | | if(isEmpty(str) || isEmpty(prefix)){ |
| | | return str; |
| | | } |
| | | if(false == str.startsWith(prefix)){ |
| | | str = prefix + str; |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 如果给定字符串不是以suffix结尾的,在尾部补充 suffix |
| | | * @param str 字符串 |
| | | * @param suffix 后缀 |
| | | * @return 补充后的字符串 |
| | | */ |
| | | public static String addSuffixIfNot(String str, String suffix){ |
| | | if(isEmpty(str) || isEmpty(suffix)){ |
| | | return str; |
| | | } |
| | | if(false == str.endsWith(suffix)){ |
| | | str += suffix; |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 清理空白字符 |
| | | * |
| | | * @param str 被清理的字符串 |
| | | * @return 清理后的字符串 |
| | | */ |
| | | public static String cleanBlank(String str) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | |
| | | return str.replaceAll("\\s*", EMPTY); |
| | | } |
| | | |
| | | /** |
| | | * 切分字符串<br> |
| | | * a#b#c -> [a,b,c] <br> |
| | | * a##b#c -> [a,"",b,c] |
| | | * |
| | | * @param str 被切分的字符串 |
| | | * @param separator 分隔符字符 |
| | | * @return 切分后的集合 |
| | | */ |
| | | public static List<String> split(String str, char separator) { |
| | | return split(str, separator, 0); |
| | | } |
| | | |
| | | /** |
| | | * 切分字符串 |
| | | * |
| | | * @param str 被切分的字符串 |
| | | * @param separator 分隔符字符 |
| | | * @param limit 限制分片数 |
| | | * @return 切分后的集合 |
| | | */ |
| | | public static List<String> split(String str, char separator, int limit) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | List<String> list = new ArrayList<String>(limit == 0 ? 16 : limit); |
| | | if (limit == 1) { |
| | | list.add(str); |
| | | return list; |
| | | } |
| | | |
| | | boolean isNotEnd = true; // 未结束切分的标志 |
| | | int strLen = str.length(); |
| | | StringBuilder sb = new StringBuilder(strLen); |
| | | for (int i = 0; i < strLen; i++) { |
| | | char c = str.charAt(i); |
| | | if (isNotEnd && c == separator) { |
| | | list.add(sb.toString()); |
| | | // 清空StringBuilder |
| | | sb.delete(0, sb.length()); |
| | | |
| | | // 当达到切分上限-1的量时,将所剩字符全部作为最后一个串 |
| | | if (limit != 0 && list.size() == limit - 1) { |
| | | isNotEnd = false; |
| | | } |
| | | } else { |
| | | sb.append(c); |
| | | } |
| | | } |
| | | list.add(sb.toString());// 加入尾串 |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * 切分字符串<br> |
| | | * from jodd |
| | | * |
| | | * @param str 被切分的字符串 |
| | | * @param delimiter 分隔符 |
| | | * @return 字符串 |
| | | */ |
| | | public static String[] split(String str, String delimiter) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | if (str.trim().length() == 0) { |
| | | return new String[] { str }; |
| | | } |
| | | |
| | | int dellen = delimiter.length(); // del length |
| | | int maxparts = (str.length() / dellen) + 2; // one more for the last |
| | | int[] positions = new int[maxparts]; |
| | | |
| | | int i, j = 0; |
| | | int count = 0; |
| | | positions[0] = -dellen; |
| | | while ((i = str.indexOf(delimiter, j)) != -1) { |
| | | count++; |
| | | positions[count] = i; |
| | | j = i + dellen; |
| | | } |
| | | count++; |
| | | positions[count] = str.length(); |
| | | |
| | | String[] result = new String[count]; |
| | | |
| | | for (i = 0; i < count; i++) { |
| | | result[i] = str.substring(positions[i] + dellen, positions[i + 1]); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 改进JDK subString<br> |
| | | * index从0开始计算,最后一个字符为-1<br> |
| | | * 如果from和to位置一样,返回 "" <br> |
| | | * 如果from或to为负数,则按照length从后向前数位置,如果绝对值大于字符串长度,则from归到0,to归到length<br> |
| | | * 如果经过修正的index中from大于to,则互换from和to |
| | | * example: <br> |
| | | * abcdefgh 2 3 -> c <br> |
| | | * abcdefgh 2 -3 -> cde <br> |
| | | * |
| | | * @param string String |
| | | * @param fromIndex 开始的index(包括) |
| | | * @param toIndex 结束的index(不包括) |
| | | * @return 字串 |
| | | */ |
| | | public static String sub(String string, int fromIndex, int toIndex) { |
| | | int len = string.length(); |
| | | if (fromIndex < 0) { |
| | | fromIndex = len + fromIndex; |
| | | if(fromIndex < 0 ) { |
| | | fromIndex = 0; |
| | | } |
| | | } else if(fromIndex >= len) { |
| | | fromIndex = len -1; |
| | | } |
| | | if (toIndex < 0) { |
| | | toIndex = len + toIndex; |
| | | if(toIndex < 0) { |
| | | toIndex = len; |
| | | } |
| | | } else if(toIndex > len) { |
| | | toIndex = len; |
| | | } |
| | | if (toIndex < fromIndex) { |
| | | int tmp = fromIndex; |
| | | fromIndex = toIndex; |
| | | toIndex = tmp; |
| | | } |
| | | if (fromIndex == toIndex) { |
| | | return EMPTY; |
| | | } |
| | | char[] strArray = string.toCharArray(); |
| | | char[] newStrArray = Arrays.copyOfRange(strArray, fromIndex, toIndex); |
| | | return new String(newStrArray); |
| | | } |
| | | |
| | | /** |
| | | * 切割前部分 |
| | | * |
| | | * @param string 字符串 |
| | | * @param toIndex 切割到的位置(不包括) |
| | | * @return 切割后的字符串 |
| | | */ |
| | | public static String subPre(String string, int toIndex) { |
| | | return sub(string, 0, toIndex); |
| | | } |
| | | |
| | | /** |
| | | * 切割后部分 |
| | | * |
| | | * @param string 字符串 |
| | | * @param fromIndex 切割开始的位置(包括) |
| | | * @return 切割后的字符串 |
| | | */ |
| | | public static String subSuf(String string, int fromIndex) { |
| | | if (isEmpty(string)) { |
| | | return null; |
| | | } |
| | | return sub(string, fromIndex, string.length()); |
| | | } |
| | | |
| | | /** |
| | | * 给定字符串是否被字符包围 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @param suffix 后缀 |
| | | * @return 是否包围,空串不包围 |
| | | */ |
| | | public static boolean isSurround(String str, String prefix, String suffix) { |
| | | if (StrKit.isBlank(str)) { |
| | | return false; |
| | | } |
| | | if (str.length() < (prefix.length() + suffix.length())) { |
| | | return false; |
| | | } |
| | | |
| | | return str.startsWith(prefix) && str.endsWith(suffix); |
| | | } |
| | | |
| | | /** |
| | | * 给定字符串是否被字符包围 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @param suffix 后缀 |
| | | * @return 是否包围,空串不包围 |
| | | */ |
| | | public static boolean isSurround(String str, char prefix, char suffix) { |
| | | if (StrKit.isBlank(str)) { |
| | | return false; |
| | | } |
| | | if (str.length() < 2) { |
| | | return false; |
| | | } |
| | | |
| | | return str.charAt(0) == prefix && str.charAt(str.length() - 1) == suffix; |
| | | } |
| | | |
| | | /** |
| | | * 重复某个字符 |
| | | * |
| | | * @param c 被重复的字符 |
| | | * @param count 重复的数目 |
| | | * @return 重复字符字符串 |
| | | */ |
| | | public static String repeat(char c, int count) { |
| | | char[] result = new char[count]; |
| | | for (int i = 0; i < count; i++) { |
| | | result[i] = c; |
| | | } |
| | | return new String(result); |
| | | } |
| | | |
| | | /** |
| | | * 重复某个字符串 |
| | | * |
| | | * @param str 被重复的字符 |
| | | * @param count 重复的数目 |
| | | * @return 重复字符字符串 |
| | | */ |
| | | public static String repeat(String str, int count) { |
| | | |
| | | // 检查 |
| | | final int len = str.length(); |
| | | final long longSize = (long) len * (long) count; |
| | | final int size = (int) longSize; |
| | | if (size != longSize) { |
| | | throw new ArrayIndexOutOfBoundsException("Required String length is too large: " + longSize); |
| | | } |
| | | |
| | | final char[] array = new char[size]; |
| | | str.getChars(0, len, array, 0); |
| | | int n; |
| | | for (n = len; n < size - n; n <<= 1) {// n <<= 1相当于n *2 |
| | | System.arraycopy(array, 0, array, n, n); |
| | | } |
| | | System.arraycopy(array, 0, array, n, size - n); |
| | | return new String(array); |
| | | } |
| | | |
| | | /** |
| | | * 比较两个字符串(大小写敏感)。 |
| | | * |
| | | * <pre> |
| | | * equals(null, null) = true |
| | | * equals(null, "abc") = false |
| | | * equals("abc", null) = false |
| | | * equals("abc", "abc") = true |
| | | * equals("abc", "ABC") = false |
| | | * </pre> |
| | | * |
| | | * @param str1 要比较的字符串1 |
| | | * @param str2 要比较的字符串2 |
| | | * |
| | | * @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code> |
| | | */ |
| | | public static boolean equals(String str1, String str2) { |
| | | if (str1 == null) { |
| | | return str2 == null; |
| | | } |
| | | |
| | | return str1.equals(str2); |
| | | } |
| | | |
| | | /** |
| | | * 比较两个字符串(大小写不敏感)。 |
| | | * |
| | | * <pre> |
| | | * equalsIgnoreCase(null, null) = true |
| | | * equalsIgnoreCase(null, "abc") = false |
| | | * equalsIgnoreCase("abc", null) = false |
| | | * equalsIgnoreCase("abc", "abc") = true |
| | | * equalsIgnoreCase("abc", "ABC") = true |
| | | * </pre> |
| | | * |
| | | * @param str1 要比较的字符串1 |
| | | * @param str2 要比较的字符串2 |
| | | * |
| | | * @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code> |
| | | */ |
| | | public static boolean equalsIgnoreCase(String str1, String str2) { |
| | | if (str1 == null) { |
| | | return str2 == null; |
| | | } |
| | | |
| | | return str1.equalsIgnoreCase(str2); |
| | | } |
| | | |
| | | /** |
| | | * 格式化文本, {} 表示占位符<br> |
| | | * 例如:format("aaa {} ccc", "bbb") ----> aaa bbb ccc |
| | | * |
| | | * @param template 文本模板,被替换的部分用 {} 表示 |
| | | * @param values 参数值 |
| | | * @return 格式化后的文本 |
| | | */ |
| | | public static String format(String template, Object... values) { |
| | | if (CollectionKit.isEmpty(values) || isBlank(template)) { |
| | | return template; |
| | | } |
| | | |
| | | final StringBuilder sb = new StringBuilder(); |
| | | final int length = template.length(); |
| | | |
| | | int valueIndex = 0; |
| | | char currentChar; |
| | | for (int i = 0; i < length; i++) { |
| | | if (valueIndex >= values.length) { |
| | | sb.append(sub(template, i, length)); |
| | | break; |
| | | } |
| | | |
| | | currentChar = template.charAt(i); |
| | | if (currentChar == '{') { |
| | | final char nextChar = template.charAt(++i); |
| | | if (nextChar == '}') { |
| | | sb.append(values[valueIndex++]); |
| | | } else { |
| | | sb.append('{').append(nextChar); |
| | | } |
| | | } else { |
| | | sb.append(currentChar); |
| | | } |
| | | |
| | | } |
| | | |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 格式化文本,使用 {varName} 占位<br> |
| | | * map = {a: "aValue", b: "bValue"} |
| | | * format("{a} and {b}", map) ----> aValue and bValue |
| | | * |
| | | * @param template 文本模板,被替换的部分用 {key} 表示 |
| | | * @param map 参数值对 |
| | | * @return 格式化后的文本 |
| | | */ |
| | | public static String format(String template, Map<?, ?> map) { |
| | | if (null == map || map.isEmpty()) { |
| | | return template; |
| | | } |
| | | |
| | | for (Entry<?, ?> entry : map.entrySet()) { |
| | | template = template.replace("{" + entry.getKey() + "}", entry.getValue().toString()); |
| | | } |
| | | return template; |
| | | } |
| | | |
| | | /** |
| | | * 编码字符串 |
| | | * |
| | | * @param str 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 编码后的字节码 |
| | | */ |
| | | public static byte[] bytes(String str, String charset) { |
| | | return bytes(str, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset)); |
| | | } |
| | | |
| | | /** |
| | | * 编码字符串 |
| | | * |
| | | * @param str 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 编码后的字节码 |
| | | */ |
| | | public static byte[] bytes(String str, Charset charset) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | |
| | | if (null == charset) { |
| | | return str.getBytes(); |
| | | } |
| | | return str.getBytes(charset); |
| | | } |
| | | |
| | | /** |
| | | * 将byte数组转为字符串 |
| | | * |
| | | * @param bytes byte数组 |
| | | * @param charset 字符集 |
| | | * @return 字符串 |
| | | */ |
| | | public static String str(byte[] bytes, String charset) { |
| | | return str(bytes, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset)); |
| | | } |
| | | |
| | | /** |
| | | * 解码字节码 |
| | | * |
| | | * @param data 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 解码后的字符串 |
| | | */ |
| | | public static String str(byte[] data, Charset charset) { |
| | | if (data == null) { |
| | | return null; |
| | | } |
| | | |
| | | if (null == charset) { |
| | | return new String(data); |
| | | } |
| | | return new String(data, charset); |
| | | } |
| | | |
| | | /** |
| | | * 将编码的byteBuffer数据转换为字符串 |
| | | * @param data 数据 |
| | | * @param charset 字符集,如果为空使用当前系统字符集 |
| | | * @return 字符串 |
| | | */ |
| | | public static String str(ByteBuffer data, String charset){ |
| | | if(data == null) { |
| | | return null; |
| | | } |
| | | |
| | | return str(data, Charset.forName(charset)); |
| | | } |
| | | |
| | | /** |
| | | * 将编码的byteBuffer数据转换为字符串 |
| | | * @param data 数据 |
| | | * @param charset 字符集,如果为空使用当前系统字符集 |
| | | * @return 字符串 |
| | | */ |
| | | public static String str(ByteBuffer data, Charset charset){ |
| | | if(null == charset) { |
| | | charset = Charset.defaultCharset(); |
| | | } |
| | | return charset.decode(data).toString(); |
| | | } |
| | | |
| | | /** |
| | | * 字符串转换为byteBuffer |
| | | * @param str 字符串 |
| | | * @param charset 编码 |
| | | * @return byteBuffer |
| | | */ |
| | | public static ByteBuffer byteBuffer(String str, String charset) { |
| | | return ByteBuffer.wrap(StrKit.bytes(str, charset)); |
| | | } |
| | | |
| | | /** |
| | | * 以 conjunction 为分隔符将多个对象转换为字符串 |
| | | * |
| | | * @param conjunction 分隔符 |
| | | * @param objs 数组 |
| | | * @return 连接后的字符串 |
| | | */ |
| | | public static String join(String conjunction, Object... objs) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | boolean isFirst = true; |
| | | for (Object item : objs) { |
| | | if (isFirst) { |
| | | isFirst = false; |
| | | } else { |
| | | sb.append(conjunction); |
| | | } |
| | | sb.append(item); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。</br> |
| | | * 例如:HelloWorld->hello_world |
| | | * |
| | | * @param camelCaseStr 转换前的驼峰式命名的字符串 |
| | | * @return 转换后下划线大写方式命名的字符串 |
| | | */ |
| | | public static String toUnderlineCase(String camelCaseStr) { |
| | | if (camelCaseStr == null) { |
| | | return null; |
| | | } |
| | | |
| | | final int length = camelCaseStr.length(); |
| | | StringBuilder sb = new StringBuilder(); |
| | | char c; |
| | | boolean isPreUpperCase = false; |
| | | for (int i = 0; i < length; i++) { |
| | | c = camelCaseStr.charAt(i); |
| | | boolean isNextUpperCase = true; |
| | | if (i < (length - 1)) { |
| | | isNextUpperCase = Character.isUpperCase(camelCaseStr.charAt(i + 1)); |
| | | } |
| | | if (Character.isUpperCase(c)) { |
| | | if (!isPreUpperCase || !isNextUpperCase) { |
| | | if (i > 0) sb.append(UNDERLINE); |
| | | } |
| | | isPreUpperCase = true; |
| | | } else { |
| | | isPreUpperCase = false; |
| | | } |
| | | sb.append(Character.toLowerCase(c)); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br> |
| | | * 例如:hello_world->HelloWorld |
| | | * |
| | | * @param name 转换前的下划线大写方式命名的字符串 |
| | | * @return 转换后的驼峰式命名的字符串 |
| | | */ |
| | | public static String toCamelCase(String name) { |
| | | if (name == null) { |
| | | return null; |
| | | } |
| | | if (name.contains(UNDERLINE)) { |
| | | name = name.toLowerCase(); |
| | | |
| | | StringBuilder sb = new StringBuilder(name.length()); |
| | | boolean upperCase = false; |
| | | for (int i = 0; i < name.length(); i++) { |
| | | char c = name.charAt(i); |
| | | |
| | | if (c == '_') { |
| | | upperCase = true; |
| | | } else if (upperCase) { |
| | | sb.append(Character.toUpperCase(c)); |
| | | upperCase = false; |
| | | } else { |
| | | sb.append(c); |
| | | } |
| | | } |
| | | return sb.toString(); |
| | | } else |
| | | return name; |
| | | } |
| | | |
| | | /** |
| | | * 包装指定字符串 |
| | | * |
| | | * @param str 被包装的字符串 |
| | | * @param prefix 前缀 |
| | | * @param suffix 后缀 |
| | | * @return 包装后的字符串 |
| | | */ |
| | | public static String wrap(String str, String prefix, String suffix) { |
| | | return format("{}{}{}", prefix, str, suffix); |
| | | } |
| | | |
| | | /** |
| | | * 指定字符串是否被包装 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @param suffix 后缀 |
| | | * @return 是否被包装 |
| | | */ |
| | | public static boolean isWrap(String str, String prefix, String suffix) { |
| | | return str.startsWith(prefix) && str.endsWith(suffix); |
| | | } |
| | | |
| | | /** |
| | | * 指定字符串是否被同一字符包装(前后都有这些字符串) |
| | | * |
| | | * @param str 字符串 |
| | | * @param wrapper 包装字符串 |
| | | * @return 是否被包装 |
| | | */ |
| | | public static boolean isWrap(String str, String wrapper) { |
| | | return isWrap(str, wrapper, wrapper); |
| | | } |
| | | |
| | | /** |
| | | * 指定字符串是否被同一字符包装(前后都有这些字符串) |
| | | * |
| | | * @param str 字符串 |
| | | * @param wrapper 包装字符 |
| | | * @return 是否被包装 |
| | | */ |
| | | public static boolean isWrap(String str, char wrapper) { |
| | | return isWrap(str, wrapper, wrapper); |
| | | } |
| | | |
| | | /** |
| | | * 指定字符串是否被包装 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefixChar 前缀 |
| | | * @param suffixChar 后缀 |
| | | * @return 是否被包装 |
| | | */ |
| | | public static boolean isWrap(String str, char prefixChar, char suffixChar) { |
| | | return str.charAt(0) == prefixChar && str.charAt(str.length() - 1) == suffixChar; |
| | | } |
| | | |
| | | /** |
| | | * 补充字符串以满足最小长度 StrUtil.padPre("1", 3, '0');//"001" |
| | | * |
| | | * @param str 字符串 |
| | | * @param minLength 最小长度 |
| | | * @param padChar 补充的字符 |
| | | * @return 补充后的字符串 |
| | | */ |
| | | public static String padPre(String str, int minLength, char padChar) { |
| | | if (str.length() >= minLength) { |
| | | return str; |
| | | } |
| | | StringBuilder sb = new StringBuilder(minLength); |
| | | for (int i = str.length(); i < minLength; i++) { |
| | | sb.append(padChar); |
| | | } |
| | | sb.append(str); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 补充字符串以满足最小长度 StrUtil.padEnd("1", 3, '0');//"100" |
| | | * |
| | | * @param str 字符串 |
| | | * @param minLength 最小长度 |
| | | * @param padChar 补充的字符 |
| | | * @return 补充后的字符串 |
| | | */ |
| | | public static String padEnd(String str, int minLength, char padChar) { |
| | | if (str.length() >= minLength) { |
| | | return str; |
| | | } |
| | | StringBuilder sb = new StringBuilder(minLength); |
| | | sb.append(str); |
| | | for (int i = str.length(); i < minLength; i++) { |
| | | sb.append(padChar); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 创建StringBuilder对象 |
| | | * |
| | | * @return StringBuilder对象 |
| | | */ |
| | | public static StringBuilder builder() { |
| | | return new StringBuilder(); |
| | | } |
| | | |
| | | /** |
| | | * 创建StringBuilder对象 |
| | | * |
| | | * @return StringBuilder对象 |
| | | */ |
| | | public static StringBuilder builder(int capacity) { |
| | | return new StringBuilder(capacity); |
| | | } |
| | | |
| | | /** |
| | | * 创建StringBuilder对象 |
| | | * |
| | | * @return StringBuilder对象 |
| | | */ |
| | | public static StringBuilder builder(String... strs) { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | for (String str : strs) { |
| | | sb.append(str); |
| | | } |
| | | return sb; |
| | | } |
| | | |
| | | /** |
| | | * 获得StringReader |
| | | * |
| | | * @param str 字符串 |
| | | * @return StringReader |
| | | */ |
| | | public static StringReader getReader(String str) { |
| | | return new StringReader(str); |
| | | } |
| | | |
| | | /** |
| | | * 获得StringWriter |
| | | * |
| | | * @return StringWriter |
| | | */ |
| | | public static StringWriter getWriter() { |
| | | return new StringWriter(); |
| | | } |
| | | |
| | | /** |
| | | * 编码字符串 |
| | | * |
| | | * @param str 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 编码后的字节码 |
| | | */ |
| | | public static byte[] encode(String str, String charset) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | |
| | | if(isBlank(charset)) { |
| | | return str.getBytes(); |
| | | } |
| | | try { |
| | | return str.getBytes(charset); |
| | | } catch (UnsupportedEncodingException e) { |
| | | throw new RuntimeException(format("Charset [{}] unsupported!", charset)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 解码字节码 |
| | | * |
| | | * @param data 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 解码后的字符串 |
| | | */ |
| | | public static String decode(byte[] data, String charset) { |
| | | if (data == null) { |
| | | return null; |
| | | } |
| | | |
| | | if(isBlank(charset)) { |
| | | return new String(data); |
| | | } |
| | | try { |
| | | return new String(data, charset); |
| | | } catch (UnsupportedEncodingException e) { |
| | | throw new RuntimeException(format("Charset [{}] unsupported!", charset)); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2011-2014, hubin (jobob@qq.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * Web防火墙工具类 |
| | | * <p> |
| | | * @author hubin |
| | | * @Date 2014-5-8 |
| | | */ |
| | | public class WafKit { |
| | | |
| | | /** |
| | | * @Description 过滤XSS脚本内容 |
| | | * @param value |
| | | * 待处理内容 |
| | | * @return |
| | | */ |
| | | public static String stripXSS(String value) { |
| | | String rlt = null; |
| | | |
| | | if (null != value) { |
| | | // NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to |
| | | // avoid encoded attacks. |
| | | // value = ESAPI.encoder().canonicalize(value); |
| | | |
| | | // Avoid null characters |
| | | rlt = value.replaceAll("", ""); |
| | | |
| | | // Avoid anything between script tags |
| | | Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | |
| | | // Avoid anything in a src='...' type of expression |
| | | /*scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE |
| | | | Pattern.MULTILINE | Pattern.DOTALL); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | |
| | | scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE |
| | | | Pattern.MULTILINE | Pattern.DOTALL); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll("");*/ |
| | | |
| | | // Remove any lonesome </script> tag |
| | | scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | |
| | | // Remove any lonesome <script ...> tag |
| | | scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE |
| | | | Pattern.MULTILINE | Pattern.DOTALL); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | |
| | | // Avoid eval(...) expressions |
| | | scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE |
| | | | Pattern.MULTILINE | Pattern.DOTALL); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | |
| | | // Avoid expression(...) expressions |
| | | scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE |
| | | | Pattern.MULTILINE | Pattern.DOTALL); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | |
| | | // Avoid javascript:... expressions |
| | | scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | |
| | | // Avoid vbscript:... expressions |
| | | scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | |
| | | // Avoid onload= expressions |
| | | scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE |
| | | | Pattern.MULTILINE | Pattern.DOTALL); |
| | | rlt = scriptPattern.matcher(rlt).replaceAll(""); |
| | | } |
| | | |
| | | return rlt; |
| | | } |
| | | |
| | | /** |
| | | * @Description 过滤SQL注入内容 |
| | | * @param value |
| | | * 待处理内容 |
| | | * @return |
| | | */ |
| | | public static String stripSqlInjection(String value) { |
| | | return (null == value) ? null : value.replaceAll("('.+--)|(--)|(%7C)", ""); //value.replaceAll("('.+--)|(--)|(\\|)|(%7C)", ""); |
| | | } |
| | | |
| | | /** |
| | | * @Description 过滤SQL/XSS注入内容 |
| | | * @param value |
| | | * 待处理内容 |
| | | * @return |
| | | */ |
| | | public static String stripSqlXSS(String value) { |
| | | return stripXSS(stripSqlInjection(value)); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2011-2014, hubin (jobob@qq.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| | | * use this file except in compliance with the License. You may obtain a copy of |
| | | * the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| | | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| | | * License for the specific language governing permissions and limitations under |
| | | * the License. |
| | | */ |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import javax.servlet.http.Cookie; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletRequestWrapper; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * Request请求过滤包装 |
| | | * <p> |
| | | * @author hubin |
| | | * @Date 2014-5-8 |
| | | */ |
| | | public class WafRequestWrapper extends HttpServletRequestWrapper { |
| | | |
| | | private boolean filterXSS = true; |
| | | |
| | | private boolean filterSQL = true; |
| | | |
| | | |
| | | public WafRequestWrapper(HttpServletRequest request, boolean filterXSS, boolean filterSQL) { |
| | | super(request); |
| | | this.filterXSS = filterXSS; |
| | | this.filterSQL = filterSQL; |
| | | } |
| | | |
| | | |
| | | public WafRequestWrapper(HttpServletRequest request) { |
| | | this(request, true, true); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @Description 数组参数过滤 |
| | | * @param parameter |
| | | * 过滤参数 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public String[] getParameterValues(String parameter) { |
| | | String[] values = super.getParameterValues(parameter); |
| | | if ( values == null ) { |
| | | return null; |
| | | } |
| | | |
| | | int count = values.length; |
| | | String[] encodedValues = new String[count]; |
| | | for ( int i = 0 ; i < count ; i++ ) { |
| | | encodedValues[i] = filterParamString(values[i]); |
| | | } |
| | | |
| | | return encodedValues; |
| | | } |
| | | |
| | | @Override |
| | | @SuppressWarnings({ "rawtypes", "unchecked" }) |
| | | public Map getParameterMap() { |
| | | Map<String, String[]> primary = super.getParameterMap(); |
| | | Map<String, String[]> result = new HashMap<String, String[]>(primary.size()); |
| | | for ( Map.Entry<String, String[]> entry : primary.entrySet() ) { |
| | | result.put(entry.getKey(), filterEntryString(entry.getValue())); |
| | | } |
| | | return result; |
| | | |
| | | } |
| | | |
| | | protected String[] filterEntryString(String[] rawValue) { |
| | | for ( int i = 0 ; i < rawValue.length ; i++ ) { |
| | | rawValue[i] = filterParamString(rawValue[i]); |
| | | } |
| | | return rawValue; |
| | | } |
| | | |
| | | /** |
| | | * @Description 参数过滤 |
| | | * @param parameter |
| | | * 过滤参数 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public String getParameter(String parameter) { |
| | | return filterParamString(super.getParameter(parameter)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @Description 请求头过滤 |
| | | * @param name |
| | | * 过滤内容 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public String getHeader(String name) { |
| | | return filterParamString(super.getHeader(name)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @Description Cookie内容过滤 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Cookie[] getCookies() { |
| | | Cookie[] existingCookies = super.getCookies(); |
| | | if (existingCookies != null) { |
| | | for (int i = 0 ; i < existingCookies.length ; ++i) { |
| | | Cookie cookie = existingCookies[i]; |
| | | cookie.setValue(filterParamString(cookie.getValue())); |
| | | } |
| | | } |
| | | return existingCookies; |
| | | } |
| | | |
| | | /** |
| | | * @Description 过滤字符串内容 |
| | | * @param rawValue |
| | | * 待处理内容 |
| | | * @return |
| | | */ |
| | | protected String filterParamString(String rawValue) { |
| | | if (null == rawValue) { |
| | | return null; |
| | | } |
| | | String tmpStr = rawValue; |
| | | if (this.filterXSS) { |
| | | tmpStr = WafKit.stripXSS(rawValue); |
| | | } |
| | | if (this.filterSQL) { |
| | | tmpStr = WafKit.stripSqlInjection(tmpStr); |
| | | } |
| | | return tmpStr; |
| | | } |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.support.exception; |
| | | |
| | | import com.stylefeng.guns.core.support.StrKit; |
| | | |
| | | /** |
| | | * 工具类初始化异常 |
| | | */ |
| | | public class ToolBoxException extends RuntimeException{ |
| | | private static final long serialVersionUID = 8247610319171014183L; |
| | | |
| | | public ToolBoxException(Throwable e) { |
| | | super(e.getMessage(), e); |
| | | } |
| | | |
| | | public ToolBoxException(String message) { |
| | | super(message); |
| | | } |
| | | |
| | | public ToolBoxException(String messageTemplate, Object... params) { |
| | | super(StrKit.format(messageTemplate, params)); |
| | | } |
| | | |
| | | public ToolBoxException(String message, Throwable throwable) { |
| | | super(message, throwable); |
| | | } |
| | | |
| | | public ToolBoxException(Throwable throwable, String messageTemplate, Object... params) { |
| | | super(StrKit.format(messageTemplate, params), throwable); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import com.stylefeng.guns.core.support.*; |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.math.BigDecimal; |
| | | import java.math.BigInteger; |
| | | import java.nio.charset.Charset; |
| | | import java.text.NumberFormat; |
| | | import java.util.Date; |
| | | import java.util.Set; |
| | | |
| | | |
| | | /** |
| | | * 类型转换器 |
| | | * |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class Convert { |
| | | |
| | | |
| | | private Convert() { |
| | | // 静态类不可实例化 |
| | | } |
| | | |
| | | /** |
| | | * 强制转换类型 |
| | | * |
| | | * @param clazz 被转换成的类型 |
| | | * @param value 需要转换的对象 |
| | | * @return 转换后的对象 |
| | | */ |
| | | public static Object parse(Class<?> clazz, Object value) { |
| | | try { |
| | | if (clazz.isAssignableFrom(String.class)) { |
| | | // ----2016-12-19---zhuangqian----防止beetlsql对空字符串不检测导致无法入库的问题---- |
| | | if (StrKit.isBlank(String.valueOf(value))) |
| | | return " "; |
| | | else |
| | | return String.valueOf(value); |
| | | } |
| | | return clazz.cast(value); |
| | | } catch (ClassCastException e) { |
| | | String valueStr = String.valueOf(value); |
| | | |
| | | Object result = parseBasic(clazz, valueStr); |
| | | if (result != null) { |
| | | return result; |
| | | } |
| | | |
| | | if (Date.class.isAssignableFrom(clazz)) { |
| | | // 判断标准日期 |
| | | // ----2016-11-24---zhuangqian----需要加toDate(),不然beetlsql转换date类型的时候会报错---- |
| | | return DateTimeKit.parse(valueStr).toDate(); |
| | | } else if (clazz == BigInteger.class) { |
| | | // 数学计算数字 |
| | | return new BigInteger(valueStr); |
| | | } else if (clazz == BigDecimal.class) { |
| | | // 数学计算数字 |
| | | return new BigDecimal(valueStr); |
| | | } else if (clazz == byte[].class) { |
| | | // 流,由于有字符编码问题,在此使用系统默认 |
| | | return valueStr.getBytes(); |
| | | } |
| | | // 未找到可转换的类型,返回原值 |
| | | return (StrKit.isBlank(valueStr)) ? null : value; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换基本类型<br> |
| | | * 将字符串转换为原始类型或包装类型 |
| | | * |
| | | * @param clazz 转换到的类,可以是原始类型类,也可以是包装类型类 |
| | | * @param valueStr 被转换的字符串 |
| | | * @return 转换后的对象,如果非基本类型,返回null |
| | | */ |
| | | public static Object parseBasic(Class<?> clazz, String valueStr) { |
| | | if (null == clazz || null == valueStr) { |
| | | return null; |
| | | } |
| | | |
| | | if (StrKit.isBlank(valueStr)) return null; |
| | | |
| | | BasicType basicType = null; |
| | | try { |
| | | basicType = BasicType.valueOf(clazz.getSimpleName().toUpperCase()); |
| | | } catch (Exception e) { |
| | | // 非基本类型数据 |
| | | return null; |
| | | } |
| | | |
| | | switch (basicType) { |
| | | case BYTE: |
| | | if (clazz == byte.class) { |
| | | return Byte.parseByte(valueStr); |
| | | } |
| | | return Byte.valueOf(valueStr); |
| | | case SHORT: |
| | | if (clazz == short.class) { |
| | | return Short.parseShort(valueStr); |
| | | } |
| | | return Short.valueOf(valueStr); |
| | | case INT: |
| | | return Integer.parseInt(valueStr); |
| | | case INTEGER: |
| | | return Integer.valueOf(valueStr); |
| | | case LONG: |
| | | if (clazz == long.class) { |
| | | return new BigDecimal(valueStr).longValue(); |
| | | } |
| | | return Long.valueOf(valueStr); |
| | | case DOUBLE: |
| | | if (clazz == double.class) { |
| | | return new BigDecimal(valueStr).doubleValue(); |
| | | } |
| | | case FLOAT: |
| | | if (clazz == float.class) { |
| | | return Float.parseFloat(valueStr); |
| | | } |
| | | return Float.valueOf(valueStr); |
| | | case BOOLEAN: |
| | | if (clazz == boolean.class) { |
| | | return Boolean.parseBoolean(valueStr); |
| | | } |
| | | return Boolean.valueOf(valueStr); |
| | | case CHAR: |
| | | return valueStr.charAt(0); |
| | | case CHARACTER: |
| | | return Character.valueOf(valueStr.charAt(0)); |
| | | default: |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为字符串<br> |
| | | * 如果给定的值为null,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static String toStr(Object value, String defaultValue) { |
| | | if (null == value) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof String) { |
| | | return (String) value; |
| | | } else if (CollectionKit.isArray(value)) { |
| | | return CollectionKit.toString(value); |
| | | } |
| | | return value.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 转换为字符串<br> |
| | | * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static String toStr(Object value) { |
| | | return toStr(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为字符<br> |
| | | * 如果给定的值为null,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Character toChar(Object value, Character defaultValue) { |
| | | if (null == value) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Character) { |
| | | return (Character) value; |
| | | } |
| | | |
| | | final String valueStr = toStr(value, null); |
| | | return StrKit.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); |
| | | } |
| | | |
| | | /** |
| | | * 转换为字符<br> |
| | | * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Character toChar(Object value) { |
| | | return toChar(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为byte<br> |
| | | * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Byte toByte(Object value, Byte defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Byte) { |
| | | return (Byte) value; |
| | | } |
| | | if (value instanceof Number) { |
| | | return ((Number) value).byteValue(); |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | return Byte.parseByte(valueStr); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为byte<br> |
| | | * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Byte toByte(Object value) { |
| | | return toByte(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Short<br> |
| | | * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Short toShort(Object value, Short defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Short) { |
| | | return (Short) value; |
| | | } |
| | | if (value instanceof Number) { |
| | | return ((Number) value).shortValue(); |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | return Short.parseShort(valueStr.trim()); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为Short<br> |
| | | * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Short toShort(Object value) { |
| | | return toShort(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Number<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Number toNumber(Object value, Number defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Number) { |
| | | return (Number) value; |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | return NumberFormat.getInstance().parse(valueStr); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为Number<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Number toNumber(Object value) { |
| | | return toNumber(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为int<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Integer toInt(Object value, Integer defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Integer) { |
| | | return (Integer) value; |
| | | } |
| | | if (value instanceof Number) { |
| | | return ((Number) value).intValue(); |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | return Integer.parseInt(valueStr.trim()); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为int<br> |
| | | * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Integer toInt(Object value) { |
| | | return toInt(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Integer数组<br> |
| | | * |
| | | * @param isIgnoreConvertError 是否忽略转换错误,忽略则给值null |
| | | * @param values 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Integer[] toIntArray(boolean isIgnoreConvertError, Object... values) { |
| | | if (CollectionKit.isEmpty(values)) { |
| | | return new Integer[] {}; |
| | | } |
| | | final Integer[] ints = new Integer[values.length]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | final Integer v = toInt(values[i], null); |
| | | if (null == v && isIgnoreConvertError == false) { |
| | | throw new ToolBoxException(StrKit.format("Convert [{}] to Integer error!", values[i])); |
| | | } |
| | | ints[i] = v; |
| | | } |
| | | return ints; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 转换为Integer数组<br> |
| | | * |
| | | * @param split 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Integer[] toIntArray(String str) { |
| | | return toIntArray(",", str); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Integer数组<br> |
| | | * |
| | | * @param split 分隔符 |
| | | * @param split 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Integer[] toIntArray(String split, String str) { |
| | | if (StrKit.isEmpty(str)) { |
| | | return new Integer[] {}; |
| | | } |
| | | String[] arr = str.split(split); |
| | | final Integer[] ints = new Integer[arr.length]; |
| | | for (int i = 0; i < arr.length; i++) { |
| | | final Integer v = toInt(arr[i], 0); |
| | | ints[i] = v; |
| | | } |
| | | return ints; |
| | | } |
| | | |
| | | /** |
| | | * 转换为String数组<br> |
| | | * |
| | | * @param split 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static String[] toStrArray(String str) { |
| | | return toStrArray("", str); |
| | | } |
| | | |
| | | /** |
| | | * 转换为String数组<br> |
| | | * |
| | | * @param split 分隔符 |
| | | * @param split 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static String[] toStrArray(String split, String str) { |
| | | return str.split(split); |
| | | } |
| | | |
| | | /** |
| | | * 转换为long<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Long toLong(Object value, Long defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Long) { |
| | | return (Long) value; |
| | | } |
| | | if (value instanceof Number) { |
| | | return ((Number) value).longValue(); |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | // 支持科学计数法 |
| | | return new BigDecimal(valueStr.trim()).longValue(); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为long<br> |
| | | * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Long toLong(Object value) { |
| | | return toLong(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Long数组<br> |
| | | * |
| | | * @param isIgnoreConvertError 是否忽略转换错误,忽略则给值null |
| | | * @param values 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Long[] toLongArray(boolean isIgnoreConvertError, Object... values) { |
| | | if (CollectionKit.isEmpty(values)) { |
| | | return new Long[] {}; |
| | | } |
| | | final Long[] longs = new Long[values.length]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | final Long v = toLong(values[i], null); |
| | | if (null == v && isIgnoreConvertError == false) { |
| | | throw new ToolBoxException(StrKit.format("Convert [{}] to Long error!", values[i])); |
| | | } |
| | | longs[i] = v; |
| | | } |
| | | return longs; |
| | | } |
| | | |
| | | /** |
| | | * 转换为double<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Double toDouble(Object value, Double defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Double) { |
| | | return (Double) value; |
| | | } |
| | | if (value instanceof Number) { |
| | | return ((Number) value).doubleValue(); |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | // 支持科学计数法 |
| | | return new BigDecimal(valueStr.trim()).doubleValue(); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为double<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Double toDouble(Object value) { |
| | | return toDouble(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Double数组<br> |
| | | * |
| | | * @param isIgnoreConvertError 是否忽略转换错误,忽略则给值null |
| | | * @param values 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Double[] toDoubleArray(boolean isIgnoreConvertError, Object... values) { |
| | | if (CollectionKit.isEmpty(values)) { |
| | | return new Double[] {}; |
| | | } |
| | | final Double[] doubles = new Double[values.length]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | final Double v = toDouble(values[i], null); |
| | | if (null == v && isIgnoreConvertError == false) { |
| | | throw new ToolBoxException(StrKit.format("Convert [{}] to Double error!", values[i])); |
| | | } |
| | | doubles[i] = v; |
| | | } |
| | | return doubles; |
| | | } |
| | | |
| | | /** |
| | | * 转换为Float<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Float toFloat(Object value, Float defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Float) { |
| | | return (Float) value; |
| | | } |
| | | if (value instanceof Number) { |
| | | return ((Number) value).floatValue(); |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | return Float.parseFloat(valueStr.trim()); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为Float<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Float toFloat(Object value) { |
| | | return toFloat(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Float数组<br> |
| | | * |
| | | * @param isIgnoreConvertError 是否忽略转换错误,忽略则给值null |
| | | * @param values 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static <T> Float[] toFloatArray(boolean isIgnoreConvertError, Object... values) { |
| | | if (CollectionKit.isEmpty(values)) { |
| | | return new Float[] {}; |
| | | } |
| | | final Float[] floats = new Float[values.length]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | final Float v = toFloat(values[i], null); |
| | | if (null == v && isIgnoreConvertError == false) { |
| | | throw new ToolBoxException(StrKit.format("Convert [{}] to Float error!", values[i])); |
| | | } |
| | | floats[i] = v; |
| | | } |
| | | return floats; |
| | | } |
| | | |
| | | /** |
| | | * 转换为boolean<br> |
| | | * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static Boolean toBool(Object value, Boolean defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof Boolean) { |
| | | return (Boolean) value; |
| | | } |
| | | String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | valueStr = valueStr.trim().toLowerCase(); |
| | | switch (valueStr) { |
| | | case "true": |
| | | return true; |
| | | case "false": |
| | | return false; |
| | | case "yes": |
| | | return true; |
| | | case "ok": |
| | | return true; |
| | | case "no": |
| | | return false; |
| | | case "1": |
| | | return true; |
| | | case "0": |
| | | return false; |
| | | default: |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为boolean<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Boolean toBool(Object value) { |
| | | return toBool(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Boolean数组<br> |
| | | * |
| | | * @param isIgnoreConvertError 是否忽略转换错误,忽略则给值null |
| | | * @param values 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static Boolean[] toBooleanArray(boolean isIgnoreConvertError, Object... values) { |
| | | if (CollectionKit.isEmpty(values)) { |
| | | return new Boolean[] {}; |
| | | } |
| | | final Boolean[] bools = new Boolean[values.length]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | final Boolean v = toBool(values[i], null); |
| | | if (null == v && isIgnoreConvertError == false) { |
| | | throw new ToolBoxException(StrKit.format("Convert [{}] to Boolean error!", values[i])); |
| | | } |
| | | bools[i] = v; |
| | | } |
| | | return bools; |
| | | } |
| | | |
| | | /** |
| | | * 转换为Enum对象<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * |
| | | * @param clazz Enum的Class |
| | | * @param value 值 |
| | | * @param defaultValue 默认值 |
| | | * @return Enum |
| | | */ |
| | | public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (clazz.isAssignableFrom(value.getClass())) { |
| | | @SuppressWarnings("unchecked") |
| | | E myE = (E) value; |
| | | return myE; |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | return Enum.valueOf(clazz, valueStr); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为Enum对象<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
| | | * |
| | | * @param clazz Enum的Class |
| | | * @param value 值 |
| | | * @return Enum |
| | | */ |
| | | public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) { |
| | | return toEnum(clazz, value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为BigInteger<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static BigInteger toBigInteger(Object value, BigInteger defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof BigInteger) { |
| | | return (BigInteger) value; |
| | | } |
| | | if (value instanceof Long) { |
| | | return BigInteger.valueOf((Long) value); |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | return new BigInteger(valueStr); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为BigInteger<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static BigInteger toBigInteger(Object value) { |
| | | return toBigInteger(value, null); |
| | | } |
| | | |
| | | /** |
| | | * 转换为BigDecimal<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @param defaultValue 转换错误时的默认值 |
| | | * @return 结果 |
| | | */ |
| | | public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) { |
| | | if (value == null) { |
| | | return defaultValue; |
| | | } |
| | | if (value instanceof BigDecimal) { |
| | | return (BigDecimal) value; |
| | | } |
| | | if (value instanceof Long) { |
| | | return new BigDecimal((Long) value); |
| | | } |
| | | if (value instanceof Double) { |
| | | return new BigDecimal((Double) value); |
| | | } |
| | | if (value instanceof Integer) { |
| | | return new BigDecimal((Integer) value); |
| | | } |
| | | final String valueStr = toStr(value, null); |
| | | if (StrKit.isBlank(valueStr)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | return new BigDecimal(valueStr); |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 转换为BigDecimal<br> |
| | | * 如果给定的值为空,或者转换失败,返回默认值<br> |
| | | * 转换失败不会报错 |
| | | * |
| | | * @param value 被转换的值 |
| | | * @return 结果 |
| | | */ |
| | | public static BigDecimal toBigDecimal(Object value) { |
| | | return toBigDecimal(value, null); |
| | | } |
| | | |
| | | // ----------------------------------------------------------------------- 全角半角转换 |
| | | /** |
| | | * 半角转全角 |
| | | * |
| | | * @param input String. |
| | | * @return 全角字符串. |
| | | */ |
| | | public static String toSBC(String input) { |
| | | return toSBC(input, null); |
| | | } |
| | | |
| | | /** |
| | | * 半角转全角 |
| | | * |
| | | * @param input String |
| | | * @param notConvertSet 不替换的字符集合 |
| | | * @return 全角字符串. |
| | | */ |
| | | public static String toSBC(String input, Set<Character> notConvertSet) { |
| | | char c[] = input.toCharArray(); |
| | | for (int i = 0; i < c.length; i++) { |
| | | if (null != notConvertSet && notConvertSet.contains(c[i])) { |
| | | // 跳过不替换的字符 |
| | | continue; |
| | | } |
| | | |
| | | if (c[i] == ' ') { |
| | | c[i] = '\u3000'; |
| | | } else if (c[i] < '\177') { |
| | | c[i] = (char) (c[i] + 65248); |
| | | |
| | | } |
| | | } |
| | | return new String(c); |
| | | } |
| | | |
| | | /** |
| | | * 全角转半角 |
| | | * |
| | | * @param input String. |
| | | * @return 半角字符串 |
| | | */ |
| | | public static String toDBC(String input) { |
| | | return toDBC(input, null); |
| | | } |
| | | |
| | | /** |
| | | * 替换全角为半角 |
| | | * |
| | | * @param text 文本 |
| | | * @param notConvertSet 不替换的字符集合 |
| | | * @return 替换后的字符 |
| | | */ |
| | | public static String toDBC(String text, Set<Character> notConvertSet) { |
| | | char c[] = text.toCharArray(); |
| | | for (int i = 0; i < c.length; i++) { |
| | | if (null != notConvertSet && notConvertSet.contains(c[i])) { |
| | | // 跳过不替换的字符 |
| | | continue; |
| | | } |
| | | |
| | | if (c[i] == '\u3000') { |
| | | c[i] = ' '; |
| | | } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') { |
| | | c[i] = (char) (c[i] - 65248); |
| | | } |
| | | } |
| | | String returnString = new String(c); |
| | | |
| | | return returnString; |
| | | } |
| | | |
| | | // --------------------------------------------------------------------- hex |
| | | /** |
| | | * 字符串转换成十六进制字符串 |
| | | * |
| | | * @param str 待转换的ASCII字符串 |
| | | * @return 16进制字符串 |
| | | */ |
| | | public static String toHex(String str) { |
| | | return HexKit.encodeHexStr(str.getBytes()); |
| | | } |
| | | |
| | | /** |
| | | * byte数组转16进制串 |
| | | * |
| | | * @param bytes 被转换的byte数组 |
| | | * @return 转换后的值 |
| | | */ |
| | | public static String toHex(byte[] bytes) { |
| | | return HexKit.encodeHexStr(bytes); |
| | | } |
| | | |
| | | /** |
| | | * Hex字符串转换为Byte值 |
| | | * |
| | | * @param src Byte字符串,每个Byte之间没有分隔符 |
| | | * @return byte[] |
| | | */ |
| | | public static byte[] hexToBytes(String src) { |
| | | return HexKit.decodeHex(src.toCharArray()); |
| | | } |
| | | |
| | | /** |
| | | * 十六进制转换字符串 |
| | | * |
| | | * @param hexStr Byte字符串(Byte之间无分隔符 如:[616C6B]) |
| | | * @param charset 编码 {@link Charset} |
| | | * @return 对应的字符串 |
| | | */ |
| | | public static String hexStrToStr(String hexStr, Charset charset) { |
| | | return HexKit.decodeHexStr(hexStr, charset); |
| | | } |
| | | |
| | | /** |
| | | * String的字符串转换成unicode的String |
| | | * |
| | | * @param strText 全角字符串 |
| | | * @return String 每个unicode之间无分隔符 |
| | | * @throws Exception |
| | | */ |
| | | public static String strToUnicode(String strText) throws Exception { |
| | | char c; |
| | | StringBuilder str = new StringBuilder(); |
| | | int intAsc; |
| | | String strHex; |
| | | for (int i = 0; i < strText.length(); i++) { |
| | | c = strText.charAt(i); |
| | | intAsc = (int) c; |
| | | strHex = Integer.toHexString(intAsc); |
| | | if (intAsc > 128) |
| | | str.append("\\u" + strHex); |
| | | else // 低位在前面补00 |
| | | str.append("\\u00" + strHex); |
| | | } |
| | | return str.toString(); |
| | | } |
| | | |
| | | /** |
| | | * unicode的String转换成String的字符串 |
| | | * |
| | | * @param hex 16进制值字符串 (一个unicode为2byte) |
| | | * @return String 全角字符串 |
| | | */ |
| | | public static String unicodeToStr(String hex) { |
| | | int t = hex.length() / 6; |
| | | StringBuilder str = new StringBuilder(); |
| | | for (int i = 0; i < t; i++) { |
| | | String s = hex.substring(i * 6, (i + 1) * 6); |
| | | // 高位需要补上00再转 |
| | | String s1 = s.substring(2, 4) + "00"; |
| | | // 低位直接转 |
| | | String s2 = s.substring(4); |
| | | // 将16进制的string转为int |
| | | int n = Integer.valueOf(s1, 16) + Integer.valueOf(s2, 16); |
| | | // 将int转换为字符 |
| | | char[] chars = Character.toChars(n); |
| | | str.append(new String(chars)); |
| | | } |
| | | return str.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 给定字符串转换字符编码<br/> |
| | | * 如果参数为空,则返回原字符串,不报错。 |
| | | * |
| | | * @param str 被转码的字符串 |
| | | * @param sourceCharset 原字符集 |
| | | * @param destCharset 目标字符集 |
| | | * @return 转换后的字符串 |
| | | */ |
| | | public static String convertCharset(String str, String sourceCharset, String destCharset) { |
| | | if (StrKit.hasBlank(str, sourceCharset, destCharset)) { |
| | | return str; |
| | | } |
| | | |
| | | try { |
| | | return new String(str.getBytes(sourceCharset), destCharset); |
| | | } catch (UnsupportedEncodingException e) { |
| | | return str; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 数字金额大写转换 先写个完整的然后将如零拾替换成零 |
| | | * |
| | | * @param n 数字 |
| | | * @return 中文大写数字 |
| | | */ |
| | | public static String digitUppercase(double n) { |
| | | String fraction[] = { "角", "分" }; |
| | | String digit[] = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; |
| | | String unit[][] = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } }; |
| | | |
| | | String head = n < 0 ? "负" : ""; |
| | | n = Math.abs(n); |
| | | |
| | | String s = ""; |
| | | for (int i = 0; i < fraction.length; i++) { |
| | | s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); |
| | | } |
| | | if (s.length() < 1) { |
| | | s = "整"; |
| | | } |
| | | int integerPart = (int) Math.floor(n); |
| | | |
| | | for (int i = 0; i < unit[0].length && integerPart > 0; i++) { |
| | | String p = ""; |
| | | for (int j = 0; j < unit[1].length && n > 0; j++) { |
| | | p = digit[integerPart % 10] + unit[1][j] + p; |
| | | integerPart = integerPart / 10; |
| | | } |
| | | s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; |
| | | } |
| | | return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * <p> |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * <p> |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * <p> |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.commons.lang3.time.DateFormatUtils; |
| | | import org.apache.commons.lang3.time.DateUtils; |
| | | |
| | | import java.sql.Timestamp; |
| | | import java.text.DateFormat; |
| | | import java.text.ParseException; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | |
| | | public class DateUtil { |
| | | |
| | | /** |
| | | * 获取YYYY格式 |
| | | */ |
| | | public static String getYear() { |
| | | return formatDate(new Date(), "yyyy"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYY格式 |
| | | */ |
| | | public static String getYear(Date date) { |
| | | return formatDate(date, "yyyy"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYY-MM-DD格式 |
| | | */ |
| | | public static String getDay() { |
| | | return formatDate(new Date(), "yyyy-MM-dd"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYY-MM-DD格式 |
| | | */ |
| | | public static String getDay(Date date) { |
| | | return formatDate(date, "yyyy-MM-dd"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYYMMDD格式 |
| | | */ |
| | | public static String getDays() { |
| | | return formatDate(new Date(), "yyyyMMdd"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYYMMDD格式 |
| | | */ |
| | | public static String getDays(Date date) { |
| | | return formatDate(date, "yyyyMMdd"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYY-MM-DD HH:mm:ss格式 |
| | | */ |
| | | public static String getTime() { |
| | | return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYY-MM-DD HH:mm:ss.SSS格式 |
| | | */ |
| | | public static String getMsTime() { |
| | | return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYYMMDDHHmmss格式 |
| | | */ |
| | | public static String getAllTime() { |
| | | return formatDate(new Date(), "yyyyMMddHHmmss"); |
| | | } |
| | | |
| | | /** |
| | | * 获取YYYY-MM-DD HH:mm:ss格式 |
| | | */ |
| | | public static String getTime(Date date) { |
| | | return formatDate(date, "yyyy-MM-dd HH:mm:ss"); |
| | | } |
| | | |
| | | public static String formatDate(Date date, String pattern) { |
| | | String formatDate = null; |
| | | if (StringUtils.isNotBlank(pattern)) { |
| | | formatDate = DateFormatUtils.format(date, pattern); |
| | | } else { |
| | | formatDate = DateFormatUtils.format(date, "yyyy-MM-dd"); |
| | | } |
| | | return formatDate; |
| | | } |
| | | |
| | | /** |
| | | * 日期比较,如果s>=e 返回true 否则返回false) |
| | | * |
| | | * @author luguosui |
| | | */ |
| | | public static boolean compareDate(String s, String e) { |
| | | if (parseDate(s) == null || parseDate(e) == null) { |
| | | return false; |
| | | } |
| | | return parseDate(s).getTime() >= parseDate(e).getTime(); |
| | | } |
| | | |
| | | /** |
| | | * 格式化日期 |
| | | */ |
| | | public static Date parseDate(String date) { |
| | | return parse(date, "yyyy-MM-dd"); |
| | | } |
| | | |
| | | /** |
| | | * 格式化日期 |
| | | */ |
| | | public static Date parseTimeMinutes(String date) { |
| | | return parse(date, "yyyy-MM-dd HH:mm"); |
| | | } |
| | | |
| | | /** |
| | | * 格式化日期 |
| | | */ |
| | | public static Date parseTime(String date) { |
| | | return parse(date, "yyyy-MM-dd HH:mm:ss"); |
| | | } |
| | | |
| | | /** |
| | | * 格式化日期 |
| | | */ |
| | | public static Date parse(String date, String pattern) { |
| | | try { |
| | | return DateUtils.parseDate(date, pattern); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 格式化日期 |
| | | */ |
| | | public static String format(Date date, String pattern) { |
| | | return DateFormatUtils.format(date, pattern); |
| | | } |
| | | |
| | | /** |
| | | * 把日期转换为Timestamp |
| | | */ |
| | | public static Timestamp format(Date date) { |
| | | return new Timestamp(date.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 校验日期是否合法 |
| | | */ |
| | | public static boolean isValidDate(String s) { |
| | | return parse(s, "yyyy-MM-dd HH:mm:ss") != null; |
| | | } |
| | | |
| | | /** |
| | | * 校验日期是否合法 |
| | | */ |
| | | public static boolean isValidDate(String s, String pattern) { |
| | | return parse(s, pattern) != null; |
| | | } |
| | | |
| | | public static int getDiffYear(String startTime, String endTime) { |
| | | DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd"); |
| | | try { |
| | | int years = (int) (((fmt.parse(endTime).getTime() - fmt.parse( |
| | | startTime).getTime()) / (1000 * 60 * 60 * 24)) / 365); |
| | | return years; |
| | | } catch (Exception e) { |
| | | // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对 |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * <li>功能描述:时间相减得到天数 |
| | | */ |
| | | public static long getDaySub(String beginDateStr, String endDateStr) { |
| | | long day = 0; |
| | | SimpleDateFormat format = new SimpleDateFormat( |
| | | "yyyy-MM-dd"); |
| | | Date beginDate = null; |
| | | Date endDate = null; |
| | | |
| | | try { |
| | | beginDate = format.parse(beginDateStr); |
| | | endDate = format.parse(endDateStr); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | day = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000); |
| | | // System.out.println("相隔的天数="+day); |
| | | |
| | | return day; |
| | | } |
| | | |
| | | /** |
| | | * 得到n天之后的日期 |
| | | */ |
| | | public static String getAfterDayDate(String days) { |
| | | int daysInt = Integer.parseInt(days); |
| | | |
| | | Calendar canlendar = Calendar.getInstance(); // java.util包 |
| | | canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动 |
| | | Date date = canlendar.getTime(); |
| | | |
| | | SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String dateStr = sdfd.format(date); |
| | | |
| | | return dateStr; |
| | | } |
| | | |
| | | /** |
| | | * 得到n天之后是周几 |
| | | */ |
| | | public static String getAfterDayWeek(String days) { |
| | | int daysInt = Integer.parseInt(days); |
| | | |
| | | Calendar canlendar = Calendar.getInstance(); // java.util包 |
| | | canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动 |
| | | Date date = canlendar.getTime(); |
| | | |
| | | SimpleDateFormat sdf = new SimpleDateFormat("E"); |
| | | String dateStr = sdf.format(date); |
| | | |
| | | return dateStr; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import com.stylefeng.guns.core.exception.GunsException; |
| | | import com.stylefeng.guns.core.exception.GunsExceptionEnum; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.io.File; |
| | | import java.io.FileInputStream; |
| | | import java.io.IOException; |
| | | import java.nio.ByteBuffer; |
| | | import java.nio.channels.FileChannel; |
| | | |
| | | public class FileUtil { |
| | | |
| | | private static Logger log = LoggerFactory.getLogger(FileUtil.class); |
| | | |
| | | /** |
| | | * NIO way |
| | | */ |
| | | public static byte[] toByteArray(String filename) { |
| | | |
| | | File f = new File(filename); |
| | | if (!f.exists()) { |
| | | log.error("文件未找到!" + filename); |
| | | throw new GunsException(GunsExceptionEnum.FILE_NOT_FOUND); |
| | | } |
| | | FileChannel channel = null; |
| | | FileInputStream fs = null; |
| | | try { |
| | | fs = new FileInputStream(f); |
| | | channel = fs.getChannel(); |
| | | ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size()); |
| | | while ((channel.read(byteBuffer)) > 0) { |
| | | // do nothing |
| | | // System.out.println("reading"); |
| | | } |
| | | return byteBuffer.array(); |
| | | } catch (IOException e) { |
| | | throw new GunsException(GunsExceptionEnum.FILE_READING_ERROR); |
| | | } finally { |
| | | try { |
| | | channel.close(); |
| | | } catch (IOException e) { |
| | | throw new GunsException(GunsExceptionEnum.FILE_READING_ERROR); |
| | | } |
| | | try { |
| | | fs.close(); |
| | | } catch (IOException e) { |
| | | throw new GunsException(GunsExceptionEnum.FILE_READING_ERROR); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 删除目录 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/10/30 下午4:15 |
| | | */ |
| | | public static boolean deleteDir(File dir) { |
| | | if (dir.isDirectory()) { |
| | | String[] children = dir.list(); |
| | | for (int i = 0; i < children.length; i++) { |
| | | boolean success = deleteDir(new File(dir, children[i])); |
| | | if (!success) { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | return dir.delete(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import javax.servlet.http.HttpSession; |
| | | |
| | | /** |
| | | * 非Controller中获取当前session的工具类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月28日 上午10:24:31 |
| | | */ |
| | | public class HttpSessionHolder { |
| | | |
| | | private static ThreadLocal<HttpSession> tl = new ThreadLocal<HttpSession>(); |
| | | |
| | | public static void put(HttpSession s) { |
| | | tl.set(s); |
| | | } |
| | | |
| | | public static HttpSession get() { |
| | | return tl.get(); |
| | | } |
| | | |
| | | public static void remove() { |
| | | tl.remove(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import com.baomidou.mybatisplus.toolkit.IdWorker; |
| | | |
| | | /** |
| | | * 唯一id生成器 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-08-23 11:10 |
| | | */ |
| | | public class IdGenerator { |
| | | |
| | | public static String getId() { |
| | | return String.valueOf(IdWorker.getId()); |
| | | } |
| | | |
| | | public static long getIdLong() { |
| | | return IdWorker.getId(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import java.security.MessageDigest; |
| | | import java.security.NoSuchAlgorithmException; |
| | | |
| | | /** |
| | | * MD5加密类(封装jdk自带的md5加密方法) |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年12月2日 下午4:14:22 |
| | | */ |
| | | public class MD5Util { |
| | | |
| | | public static String encrypt(String source) { |
| | | return encodeMd5(source.getBytes()); |
| | | } |
| | | |
| | | private static String encodeMd5(byte[] source) { |
| | | try { |
| | | return encodeHex(MessageDigest.getInstance("MD5").digest(source)); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | throw new IllegalStateException(e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | | private static String encodeHex(byte[] bytes) { |
| | | StringBuffer buffer = new StringBuffer(bytes.length * 2); |
| | | for (int i = 0; i < bytes.length; i++) { |
| | | if (((int) bytes[i] & 0xff) < 0x10) |
| | | buffer.append("0"); |
| | | buffer.append(Long.toString((int) bytes[i] & 0xff, 16)); |
| | | } |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | public static void main(String[] args) { |
| | | System.out.println(encrypt("123456")); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.text.DecimalFormat; |
| | | import java.text.NumberFormat; |
| | | |
| | | /** |
| | | * 数字格式化的类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月30日 下午5:58:40 |
| | | */ |
| | | public class NumUtil { |
| | | |
| | | /** |
| | | * @Description 保留指定位数的小数(少的位数不补零) |
| | | * @author fengshuonan |
| | | */ |
| | | public static String keepRandomPoint(Double value, int n) { |
| | | if (value == null) { |
| | | value = 0.00; |
| | | return new BigDecimal(value).setScale(n, RoundingMode.HALF_UP).toString(); |
| | | } else { |
| | | return new BigDecimal(value).setScale(n, RoundingMode.HALF_UP).toString(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * @Description 浮点保留两位小数(少的位数不补零) |
| | | * @author fengshuonan |
| | | */ |
| | | public static String keep2Point(double value) { |
| | | return keepRandomPoint(value, 2); |
| | | } |
| | | |
| | | /** |
| | | * @Description 浮点保留1位小数(少的位数不补零) |
| | | * @author fengshuonan |
| | | */ |
| | | public static String keep1Point(double value) { |
| | | return keepRandomPoint(value, 1); |
| | | } |
| | | |
| | | /** |
| | | * @Description 浮点保留任意位小数(少位补零) |
| | | * @author fengshuonan |
| | | */ |
| | | public static String keepRandomPointZero(double value, int n) { |
| | | DecimalFormat df = new DecimalFormat("#0.00"); |
| | | return df.format(Double.valueOf(keepRandomPoint(value, n))); |
| | | } |
| | | |
| | | /** |
| | | * @Description 浮点保留两位小数(少位补零) |
| | | * @author fengshuonan |
| | | */ |
| | | public static String keep2PointZero(double value) { |
| | | return keepRandomPointZero(value, 2); |
| | | } |
| | | |
| | | /** |
| | | * @Description 获取任意小数点位的百分比表示 |
| | | * @author fengshuonan |
| | | */ |
| | | public static String percentRandomPoint(double value, int n) { |
| | | NumberFormat percent = NumberFormat.getPercentInstance(); |
| | | percent.setGroupingUsed(false); |
| | | percent.setMaximumFractionDigits(n); |
| | | return percent.format(value); |
| | | } |
| | | |
| | | /** |
| | | * @Description 百分比保留两位小数 |
| | | * @author fengshuonan |
| | | */ |
| | | public static String percent2Point(double value) { |
| | | return percentRandomPoint(value, 2); |
| | | } |
| | | |
| | | /** |
| | | * @Description 获取格式化经纬度后的小数(保留3位) |
| | | * @author fengshuonan |
| | | */ |
| | | public static String latLngPoint(double value) { |
| | | return keepRandomPoint(value, 3); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import java.util.Random; |
| | | |
| | | /*** |
| | | * |
| | | * 得到中文首字母 |
| | | * |
| | | * @author lxm_09 |
| | | * |
| | | */ |
| | | |
| | | public class PingYinUtil { |
| | | |
| | | public static void main(String[] args) { |
| | | String str = "这是一个测试"; |
| | | System.out.println("中文首字母:" + getPYIndexStr(str, true)); |
| | | } |
| | | |
| | | /** |
| | | * 返回首字母 |
| | | */ |
| | | public static String getPYIndexStr(String strChinese, boolean bUpCase) { |
| | | try { |
| | | StringBuffer buffer = new StringBuffer(); |
| | | byte b[] = strChinese.getBytes("GBK");// 把中文转化成byte数组 |
| | | for (int i = 0; i < b.length; i++) { |
| | | if ((b[i] & 255) > 128) { |
| | | int char1 = b[i++] & 255; |
| | | char1 <<= 8;// 左移运算符用“<<”表示,是将运算符左边的对象,向左移动运算符右边指定的位数,并且在低位补零。其实,向左移n位,就相当于乘上2的n次方 |
| | | int chart = char1 + (b[i] & 255); |
| | | buffer.append(getPYIndexChar((char) chart, bUpCase)); |
| | | continue; |
| | | } |
| | | char c = (char) b[i]; |
| | | if (!Character.isJavaIdentifierPart(c))// 确定指定字符是否可以是 Java |
| | | // 标识符中首字符以外的部分。 |
| | | c = 'A'; |
| | | buffer.append(c); |
| | | } |
| | | return buffer.toString(); |
| | | } catch (Exception e) { |
| | | System.out.println((new StringBuilder()).append("\u53D6\u4E2D\u6587\u62FC\u97F3\u6709\u9519") |
| | | .append(e.getMessage()).toString()); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 得到首字母 |
| | | */ |
| | | private static char getPYIndexChar(char strChinese, boolean bUpCase) { |
| | | |
| | | int charGBK = strChinese; |
| | | |
| | | char result; |
| | | |
| | | if (charGBK >= 45217 && charGBK <= 45252) |
| | | |
| | | result = 'A'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 45253 && charGBK <= 45760) |
| | | |
| | | result = 'B'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 45761 && charGBK <= 46317) |
| | | |
| | | result = 'C'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 46318 && charGBK <= 46825) |
| | | |
| | | result = 'D'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 46826 && charGBK <= 47009) |
| | | |
| | | result = 'E'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 47010 && charGBK <= 47296) |
| | | |
| | | result = 'F'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 47297 && charGBK <= 47613) |
| | | |
| | | result = 'G'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 47614 && charGBK <= 48118) |
| | | |
| | | result = 'H'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 48119 && charGBK <= 49061) |
| | | |
| | | result = 'J'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 49062 && charGBK <= 49323) |
| | | |
| | | result = 'K'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 49324 && charGBK <= 49895) |
| | | |
| | | result = 'L'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 49896 && charGBK <= 50370) |
| | | |
| | | result = 'M'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 50371 && charGBK <= 50613) |
| | | |
| | | result = 'N'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 50614 && charGBK <= 50621) |
| | | |
| | | result = 'O'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 50622 && charGBK <= 50905) |
| | | |
| | | result = 'P'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 50906 && charGBK <= 51386) |
| | | |
| | | result = 'Q'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 51387 && charGBK <= 51445) |
| | | |
| | | result = 'R'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 51446 && charGBK <= 52217) |
| | | |
| | | result = 'S'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 52218 && charGBK <= 52697) |
| | | |
| | | result = 'T'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 52698 && charGBK <= 52979) |
| | | |
| | | result = 'W'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 52980 && charGBK <= 53688) |
| | | |
| | | result = 'X'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 53689 && charGBK <= 54480) |
| | | |
| | | result = 'Y'; |
| | | |
| | | else |
| | | |
| | | if (charGBK >= 54481 && charGBK <= 55289) |
| | | |
| | | result = 'Z'; |
| | | |
| | | else |
| | | |
| | | result = (char) (65 + (new Random()).nextInt(25)); |
| | | |
| | | if (!bUpCase) |
| | | |
| | | result = Character.toLowerCase(result); |
| | | |
| | | return result; |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.stylefeng.guns.core.exception.GunsException; |
| | | import com.stylefeng.guns.core.exception.GunsExceptionEnum; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.io.PrintWriter; |
| | | |
| | | /** |
| | | * 渲染工具类 |
| | | * |
| | | * @author stylefeng |
| | | * @date 2017-08-25 14:13 |
| | | */ |
| | | public class RenderUtil { |
| | | |
| | | /** |
| | | * 渲染json对象 |
| | | */ |
| | | public static void renderJson(HttpServletResponse response, Object jsonObject) { |
| | | try { |
| | | response.setContentType("application/json"); |
| | | response.setCharacterEncoding("UTF-8"); |
| | | PrintWriter writer = response.getWriter(); |
| | | writer.write(JSON.toJSONString(jsonObject)); |
| | | } catch (IOException e) { |
| | | throw new GunsException(GunsExceptionEnum.WRITE_ERROR); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import org.springframework.core.io.Resource; |
| | | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; |
| | | import org.springframework.core.io.support.ResourcePatternResolver; |
| | | |
| | | import java.io.IOException; |
| | | |
| | | /** |
| | | * 资源文件相关的操作类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月17日 下午10:09:23 |
| | | */ |
| | | public class ResKit { |
| | | |
| | | /** |
| | | * @Description 批量获取ClassPath下的资源文件 |
| | | * @author fengshuonan |
| | | */ |
| | | public static Resource[] getClassPathResources(String pattern) { |
| | | ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); |
| | | try { |
| | | return resolver.getResources(pattern); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException("加载resource文件时,找不到文件,所找文件为:" + pattern); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * @Description 批量获取ClassPath下的资源文件 |
| | | * @author fengshuonan |
| | | */ |
| | | public static String getClassPathFile(String file) { |
| | | //return ResKit.class.getClassLoader().getResource(file).getPath(); |
| | | return Thread.currentThread().getContextClassLoader().getResource(file).getPath(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import java.beans.PropertyDescriptor; |
| | | import java.lang.reflect.Field; |
| | | import java.lang.reflect.Method; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * 对比两个对象的变化的工具类 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/3/31 10:36 |
| | | */ |
| | | public class SimpleContrast { |
| | | |
| | | //记录每个修改字段的分隔符 |
| | | public static final String separator = ";;;"; |
| | | |
| | | /** |
| | | * 比较两个对象,并返回不一致的信息 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/9 19:34 |
| | | */ |
| | | public static String contrastObj(Object pojo1, Object pojo2) { |
| | | String str = ""; |
| | | try { |
| | | Class clazz = pojo1.getClass(); |
| | | Field[] fields = pojo1.getClass().getDeclaredFields(); |
| | | int i = 1; |
| | | for (Field field : fields) { |
| | | if ("serialVersionUID".equals(field.getName())) { |
| | | continue; |
| | | } |
| | | PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz); |
| | | Method getMethod = pd.getReadMethod(); |
| | | Object o1 = getMethod.invoke(pojo1); |
| | | Object o2 = getMethod.invoke(pojo2); |
| | | if (o1 == null || o2 == null) { |
| | | continue; |
| | | } |
| | | if (o1 instanceof Date) { |
| | | o1 = DateUtil.getDay((Date) o1); |
| | | } |
| | | if (!o1.toString().equals(o2.toString())) { |
| | | if (i != 1) { |
| | | str += separator; |
| | | } |
| | | str += "字段名称" + field.getName() + ",旧值:" + o1 + ",新值:" + o2; |
| | | i++; |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return str; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import org.springframework.beans.BeansException; |
| | | import org.springframework.context.ApplicationContext; |
| | | import org.springframework.context.ApplicationContextAware; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月27日 下午3:32:11 |
| | | */ |
| | | @Component |
| | | public class SpringContextHolder implements ApplicationContextAware { |
| | | |
| | | private static ApplicationContext applicationContext; |
| | | |
| | | @Override |
| | | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { |
| | | SpringContextHolder.applicationContext = applicationContext; |
| | | } |
| | | |
| | | public static ApplicationContext getApplicationContext() { |
| | | assertApplicationContext(); |
| | | return applicationContext; |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public static <T> T getBean(String beanName) { |
| | | assertApplicationContext(); |
| | | return (T) applicationContext.getBean(beanName); |
| | | } |
| | | |
| | | public static <T> T getBean(Class<T> requiredType) { |
| | | assertApplicationContext(); |
| | | return applicationContext.getBean(requiredType); |
| | | } |
| | | |
| | | private static void assertApplicationContext() { |
| | | if (SpringContextHolder.applicationContext == null) { |
| | | throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!"); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * sql语句工具类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年12月6日 下午1:01:54 |
| | | */ |
| | | public class SqlUtil { |
| | | |
| | | /** |
| | | * @Description 根据集合的大小,输出相应个数"?" |
| | | * @author fengshuonan |
| | | */ |
| | | public static String parse(List<?> list) { |
| | | String str = ""; |
| | | if (list != null && list.size() > 0) { |
| | | str = str + "?"; |
| | | for (int i = 1; i < list.size(); i++) { |
| | | str = str + ",?"; |
| | | } |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | public static void main(String[] args) { |
| | | ArrayList<Object> arrayList = new ArrayList<>(); |
| | | arrayList.add(2); |
| | | arrayList.add(2); |
| | | System.out.println(parse(arrayList)); |
| | | } |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * <p> |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * <p> |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * <p> |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.util; |
| | | |
| | | import com.stylefeng.guns.core.support.StrKit; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.PrintWriter; |
| | | import java.io.StringWriter; |
| | | import java.lang.reflect.Array; |
| | | import java.math.BigDecimal; |
| | | import java.net.URISyntaxException; |
| | | import java.util.*; |
| | | import java.util.Map.Entry; |
| | | |
| | | /** |
| | | * 高频方法集合类 |
| | | */ |
| | | public class ToolUtil { |
| | | |
| | | /** |
| | | * 获取随机位数的字符串 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/8/24 14:09 |
| | | */ |
| | | public static String getRandomString(int length) { |
| | | String base = "abcdefghijklmnopqrstuvwxyz0123456789"; |
| | | Random random = new Random(); |
| | | StringBuffer sb = new StringBuffer(); |
| | | for (int i = 0; i < length; i++) { |
| | | int number = random.nextInt(base.length()); |
| | | sb.append(base.charAt(number)); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 判断一个对象是否是时间类型 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/4/18 12:55 |
| | | */ |
| | | public static String dateType(Object o) { |
| | | if (o instanceof Date) { |
| | | return DateUtil.getDay((Date) o); |
| | | } else { |
| | | return o.toString(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取异常的具体信息 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/3/30 9:21 |
| | | * @version 2.0 |
| | | */ |
| | | public static String getExceptionMsg(Exception e) { |
| | | StringWriter sw = new StringWriter(); |
| | | try { |
| | | e.printStackTrace(new PrintWriter(sw)); |
| | | } finally { |
| | | try { |
| | | sw.close(); |
| | | } catch (IOException e1) { |
| | | e1.printStackTrace(); |
| | | } |
| | | } |
| | | return sw.getBuffer().toString().replaceAll("\\$", "T"); |
| | | } |
| | | |
| | | /** |
| | | * 比较两个对象是否相等。<br> |
| | | * 相同的条件有两个,满足其一即可:<br> |
| | | * 1. obj1 == null && obj2 == null; 2. obj1.equals(obj2) |
| | | * |
| | | * @param obj1 对象1 |
| | | * @param obj2 对象2 |
| | | * @return 是否相等 |
| | | */ |
| | | public static boolean equals(Object obj1, Object obj2) { |
| | | return (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null); |
| | | } |
| | | |
| | | /** |
| | | * 计算对象长度,如果是字符串调用其length函数,集合类调用其size函数,数组调用其length属性,其他可遍历对象遍历计算长度 |
| | | * |
| | | * @param obj 被计算长度的对象 |
| | | * @return 长度 |
| | | */ |
| | | public static int length(Object obj) { |
| | | if (obj == null) { |
| | | return 0; |
| | | } |
| | | if (obj instanceof CharSequence) { |
| | | return ((CharSequence) obj).length(); |
| | | } |
| | | if (obj instanceof Collection) { |
| | | return ((Collection<?>) obj).size(); |
| | | } |
| | | if (obj instanceof Map) { |
| | | return ((Map<?, ?>) obj).size(); |
| | | } |
| | | |
| | | int count; |
| | | if (obj instanceof Iterator) { |
| | | Iterator<?> iter = (Iterator<?>) obj; |
| | | count = 0; |
| | | while (iter.hasNext()) { |
| | | count++; |
| | | iter.next(); |
| | | } |
| | | return count; |
| | | } |
| | | if (obj instanceof Enumeration) { |
| | | Enumeration<?> enumeration = (Enumeration<?>) obj; |
| | | count = 0; |
| | | while (enumeration.hasMoreElements()) { |
| | | count++; |
| | | enumeration.nextElement(); |
| | | } |
| | | return count; |
| | | } |
| | | if (obj.getClass().isArray() == true) { |
| | | return Array.getLength(obj); |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | /** |
| | | * 对象中是否包含元素 |
| | | * |
| | | * @param obj 对象 |
| | | * @param element 元素 |
| | | * @return 是否包含 |
| | | */ |
| | | public static boolean contains(Object obj, Object element) { |
| | | if (obj == null) { |
| | | return false; |
| | | } |
| | | if (obj instanceof String) { |
| | | if (element == null) { |
| | | return false; |
| | | } |
| | | return ((String) obj).contains(element.toString()); |
| | | } |
| | | if (obj instanceof Collection) { |
| | | return ((Collection<?>) obj).contains(element); |
| | | } |
| | | if (obj instanceof Map) { |
| | | return ((Map<?, ?>) obj).values().contains(element); |
| | | } |
| | | |
| | | if (obj instanceof Iterator) { |
| | | Iterator<?> iter = (Iterator<?>) obj; |
| | | while (iter.hasNext()) { |
| | | Object o = iter.next(); |
| | | if (equals(o, element)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | if (obj instanceof Enumeration) { |
| | | Enumeration<?> enumeration = (Enumeration<?>) obj; |
| | | while (enumeration.hasMoreElements()) { |
| | | Object o = enumeration.nextElement(); |
| | | if (equals(o, element)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | if (obj.getClass().isArray() == true) { |
| | | int len = Array.getLength(obj); |
| | | for (int i = 0; i < len; i++) { |
| | | Object o = Array.get(obj, i); |
| | | if (equals(o, element)) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 对象是否不为空(新增) |
| | | * |
| | | * @param obj String,List,Map,Object[],int[],long[] |
| | | * @return |
| | | */ |
| | | public static boolean isNotEmpty(Object o) { |
| | | return !isEmpty(o); |
| | | } |
| | | |
| | | /** |
| | | * 对象是否为空 |
| | | * |
| | | * @param obj String,List,Map,Object[],int[],long[] |
| | | * @return |
| | | */ |
| | | @SuppressWarnings("rawtypes") |
| | | public static boolean isEmpty(Object o) { |
| | | if (o == null) { |
| | | return true; |
| | | } |
| | | if (o instanceof String) { |
| | | if (o.toString().trim().equals("")) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof List) { |
| | | if (((List) o).size() == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof Map) { |
| | | if (((Map) o).size() == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof Set) { |
| | | if (((Set) o).size() == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof Object[]) { |
| | | if (((Object[]) o).length == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof int[]) { |
| | | if (((int[]) o).length == 0) { |
| | | return true; |
| | | } |
| | | } else if (o instanceof long[]) { |
| | | if (((long[]) o).length == 0) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 对象组中是否存在 Empty Object |
| | | * |
| | | * @param os 对象组 |
| | | * @return |
| | | */ |
| | | public static boolean isOneEmpty(Object... os) { |
| | | for (Object o : os) { |
| | | if (isEmpty(o)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 对象组中是否全是 Empty Object |
| | | * |
| | | * @param os |
| | | * @return |
| | | */ |
| | | public static boolean isAllEmpty(Object... os) { |
| | | for (Object o : os) { |
| | | if (!isEmpty(o)) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 是否为数字 |
| | | * |
| | | * @param obj |
| | | * @return |
| | | */ |
| | | public static boolean isNum(Object obj) { |
| | | try { |
| | | Integer.parseInt(obj.toString()); |
| | | } catch (Exception e) { |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 如果为空, 则调用默认值 |
| | | * |
| | | * @param str |
| | | * @return |
| | | */ |
| | | public static Object getValue(Object str, Object defaultValue) { |
| | | if (isEmpty(str)) { |
| | | return defaultValue; |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 格式化文本 |
| | | * |
| | | * @param template 文本模板,被替换的部分用 {} 表示 |
| | | * @param values 参数值 |
| | | * @return 格式化后的文本 |
| | | */ |
| | | public static String format(String template, Object... values) { |
| | | return StrKit.format(template, values); |
| | | } |
| | | |
| | | /** |
| | | * 格式化文本 |
| | | * |
| | | * @param template 文本模板,被替换的部分用 {key} 表示 |
| | | * @param map 参数值对 |
| | | * @return 格式化后的文本 |
| | | */ |
| | | public static String format(String template, Map<?, ?> map) { |
| | | return StrKit.format(template, map); |
| | | } |
| | | |
| | | /** |
| | | * 强转->string,并去掉多余空格 |
| | | * |
| | | * @param str |
| | | * @return |
| | | */ |
| | | public static String toStr(Object str) { |
| | | return toStr(str, ""); |
| | | } |
| | | |
| | | /** |
| | | * 强转->string,并去掉多余空格 |
| | | * |
| | | * @param str |
| | | * @param defaultValue |
| | | * @return |
| | | */ |
| | | public static String toStr(Object str, String defaultValue) { |
| | | if (null == str) { |
| | | return defaultValue; |
| | | } |
| | | return str.toString().trim(); |
| | | } |
| | | |
| | | /** |
| | | * 强转->int |
| | | * |
| | | * @param obj |
| | | * @return |
| | | */ |
| | | // public static int toInt(Object value) { |
| | | // return toInt(value, -1); |
| | | // } |
| | | |
| | | /** |
| | | * 强转->int |
| | | * |
| | | * @param obj |
| | | * @param defaultValue |
| | | * @return |
| | | */ |
| | | // public static int toInt(Object value, int defaultValue) { |
| | | // return Convert.toInt(value, defaultValue); |
| | | // } |
| | | |
| | | /** |
| | | * 强转->long |
| | | * |
| | | * @param obj |
| | | * @return |
| | | */ |
| | | // public static long toLong(Object value) { |
| | | // return toLong(value, -1); |
| | | // } |
| | | |
| | | /** |
| | | * 强转->long |
| | | * |
| | | * @param obj |
| | | * @param defaultValue |
| | | * @return |
| | | */ |
| | | // public static long toLong(Object value, long defaultValue) { |
| | | // return Convert.toLong(value, defaultValue); |
| | | // } |
| | | // |
| | | // public static String encodeUrl(String url) { |
| | | // return URLKit.encode(url, CharsetKit.UTF_8); |
| | | // } |
| | | // |
| | | // public static String decodeUrl(String url) { |
| | | // return URLKit.decode(url, CharsetKit.UTF_8); |
| | | // } |
| | | |
| | | /** |
| | | * map的key转为小写 |
| | | * |
| | | * @param map |
| | | * @return Map<String , Object> |
| | | */ |
| | | public static Map<String, Object> caseInsensitiveMap(Map<String, Object> map) { |
| | | Map<String, Object> tempMap = new HashMap<>(); |
| | | for (String key : map.keySet()) { |
| | | tempMap.put(key.toLowerCase(), map.get(key)); |
| | | } |
| | | return tempMap; |
| | | } |
| | | |
| | | /** |
| | | * 获取map中第一个数据值 |
| | | * |
| | | * @param <K> Key的类型 |
| | | * @param <V> Value的类型 |
| | | * @param map 数据源 |
| | | * @return 返回的值 |
| | | */ |
| | | public static <K, V> V getFirstOrNull(Map<K, V> map) { |
| | | V obj = null; |
| | | for (Entry<K, V> entry : map.entrySet()) { |
| | | obj = entry.getValue(); |
| | | if (obj != null) { |
| | | break; |
| | | } |
| | | } |
| | | return obj; |
| | | } |
| | | |
| | | /** |
| | | * 创建StringBuilder对象 |
| | | * |
| | | * @return StringBuilder对象 |
| | | */ |
| | | public static StringBuilder builder(String... strs) { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | for (String str : strs) { |
| | | sb.append(str); |
| | | } |
| | | return sb; |
| | | } |
| | | |
| | | /** |
| | | * 创建StringBuilder对象 |
| | | * |
| | | * @return StringBuilder对象 |
| | | */ |
| | | public static void builder(StringBuilder sb, String... strs) { |
| | | for (String str : strs) { |
| | | sb.append(str); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 去掉指定后缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param suffix 后缀 |
| | | * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串 |
| | | */ |
| | | public static String removeSuffix(String str, String suffix) { |
| | | if (isEmpty(str) || isEmpty(suffix)) { |
| | | return str; |
| | | } |
| | | |
| | | if (str.endsWith(suffix)) { |
| | | return str.substring(0, str.length() - suffix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 当前时间 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/7 21:56 |
| | | */ |
| | | public static String currentTime() { |
| | | return DateUtil.getTime(); |
| | | } |
| | | |
| | | /** |
| | | * 首字母大写 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/7 22:01 |
| | | */ |
| | | public static String firstLetterToUpper(String val) { |
| | | return StrKit.firstCharToUpperCase(val); |
| | | } |
| | | |
| | | /** |
| | | * 首字母小写 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/7 22:02 |
| | | */ |
| | | public static String firstLetterToLower(String val) { |
| | | return StrKit.firstCharToLowerCase(val); |
| | | } |
| | | |
| | | /** |
| | | * 判断是否是windows操作系统 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/24 22:34 |
| | | */ |
| | | public static Boolean isWinOs() { |
| | | String os = System.getProperty("os.name"); |
| | | if (os.toLowerCase().startsWith("win")) { |
| | | return true; |
| | | } else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取临时目录 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/24 22:35 |
| | | */ |
| | | public static String getTempPath() { |
| | | return System.getProperty("java.io.tmpdir"); |
| | | } |
| | | |
| | | /** |
| | | * 把一个数转化为int |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/11/15 下午11:10 |
| | | */ |
| | | public static Integer toInt(Object val) { |
| | | if (val instanceof Double) { |
| | | BigDecimal bigDecimal = new BigDecimal((Double) val); |
| | | return bigDecimal.intValue(); |
| | | } else { |
| | | return Integer.valueOf(val.toString()); |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 获取项目路径 |
| | | */ |
| | | public static String getWebRootPath(String filePath) { |
| | | try { |
| | | String path = ToolUtil.class.getClassLoader().getResource("").toURI().getPath(); |
| | | path = path.replace("/WEB-INF/classes/", ""); |
| | | path = path.replace("/target/classes/", ""); |
| | | path = path.replace("file:/", ""); |
| | | if (ToolUtil.isEmpty(filePath)) { |
| | | return path; |
| | | } else { |
| | | return path + "/" + filePath; |
| | | } |
| | | } catch (URISyntaxException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取文件后缀名 不包含点 |
| | | */ |
| | | public static String getFileSuffix(String fileWholeName) { |
| | | if (ToolUtil.isEmpty(fileWholeName)) { |
| | | return "none"; |
| | | } |
| | | int lastIndexOf = fileWholeName.lastIndexOf("."); |
| | | return fileWholeName.substring(lastIndexOf + 1); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.xss; |
| | | |
| | | |
| | | import javax.servlet.*; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.io.IOException; |
| | | import java.util.List; |
| | | |
| | | |
| | | public class XssFilter implements Filter { |
| | | |
| | | FilterConfig filterConfig = null; |
| | | |
| | | private List<String> urlExclusion = null; |
| | | |
| | | public void init(FilterConfig filterConfig) throws ServletException { |
| | | this.filterConfig = filterConfig; |
| | | } |
| | | |
| | | public void destroy() { |
| | | this.filterConfig = null; |
| | | } |
| | | |
| | | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { |
| | | HttpServletRequest httpServletRequest = (HttpServletRequest) request; |
| | | String servletPath = httpServletRequest.getServletPath(); |
| | | |
| | | if (urlExclusion != null && urlExclusion.contains(servletPath)) { |
| | | chain.doFilter(request, response); |
| | | } else { |
| | | chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response); |
| | | } |
| | | } |
| | | |
| | | public List<String> getUrlExclusion() { |
| | | return urlExclusion; |
| | | } |
| | | |
| | | public void setUrlExclusion(List<String> urlExclusion) { |
| | | this.urlExclusion = urlExclusion; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.xss; |
| | | |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletRequestWrapper; |
| | | |
| | | |
| | | public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { |
| | | |
| | | public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) { |
| | | |
| | | super(servletRequest); |
| | | |
| | | } |
| | | |
| | | public String[] getParameterValues(String parameter) { |
| | | |
| | | String[] values = super.getParameterValues(parameter); |
| | | |
| | | if (values == null) { |
| | | |
| | | return null; |
| | | |
| | | } |
| | | |
| | | int count = values.length; |
| | | |
| | | String[] encodedValues = new String[count]; |
| | | |
| | | for (int i = 0; i < count; i++) { |
| | | |
| | | encodedValues[i] = cleanXSS(values[i]); |
| | | |
| | | } |
| | | |
| | | return encodedValues; |
| | | |
| | | } |
| | | |
| | | public String getParameter(String parameter) { |
| | | |
| | | String value = super.getParameter(parameter); |
| | | |
| | | if (value == null) { |
| | | |
| | | return null; |
| | | |
| | | } |
| | | |
| | | return cleanXSS(value); |
| | | |
| | | } |
| | | |
| | | public String getHeader(String name) { |
| | | |
| | | String value = super.getHeader(name); |
| | | |
| | | if (value == null) |
| | | |
| | | return null; |
| | | |
| | | return cleanXSS(value); |
| | | |
| | | } |
| | | |
| | | private String cleanXSS(String value) { |
| | | |
| | | //You'll need to remove the spaces from the html entities below |
| | | |
| | | value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;"); |
| | | |
| | | value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;"); |
| | | |
| | | value = value.replaceAll("'", "& #39;"); |
| | | |
| | | value = value.replaceAll("eval\\((.*)\\)", ""); |
| | | |
| | | value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\""); |
| | | |
| | | value = value.replaceAll("script", ""); |
| | | |
| | | return value; |
| | | |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | # AutoConfiguration |
| | | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
| | | com.stylefeng.guns.core.base.controller.GlobalController,\ |
| | | com.stylefeng.guns.core.config.DefaultFastjsonConfig,\ |
| | | com.stylefeng.guns.core.config.DefaultProperties,\ |
| | | com.stylefeng.guns.core.config.DefaultWebConfig |
New file |
| | |
| | | #\u8FD9\u4E2A\u914D\u7F6E\u6587\u4EF6\u91CC\u5199\u5176\u4ED6\u9879\u76EE\u53EF\u80FD\u5171\u7528\u7684\u914D\u7F6E,\u53EF\u4EE5\u5728application.yml\u4E2D\u914D\u7F6E\u4FE1\u606F\u8986\u76D6\u8FD9\u91CC\u7684\u914D\u7F6E |
| | | |
| | | |
| | | ######################### springs\u9ED8\u8BA4\u914D\u7F6E ######################### |
| | | spring.aop.proxy-target-class=true |
| | | |
| | | |
| | | ###################### mybatis-plus\u9ED8\u8BA4\u914D\u7F6E ####################### |
| | | mybatis-plus.mapper-locations=classpath*:com/stylefeng/guns/**/mapping/*.xml |
| | | # 0:\u6570\u636E\u5E93ID\u81EA\u589E 1:\u7528\u6237\u8F93\u5165id 2:\u5168\u5C40\u552F\u4E00id(IdWorker) 3:\u5168\u5C40\u552F\u4E00ID(uuid) |
| | | mybatis-plus.global-config.id-type=0 |
| | | mybatis-plus.global-config.db-column-underline=false |
| | | mybatis-plus.global-config.refresh-mapper=true |
| | | mybatis-plus.global-config.logic-delete-value=0 |
| | | mybatis-plus.global-config.logic-not-delete-value=1 |
| | | mybatis-plus.global-config.sql-injector=com.baomidou.mybatisplus.mapper.LogicSqlInjector |
| | | mybatis-plus.configuration.map-underscore-to-camel-case=false |
| | | #\u914D\u7F6E\u7684\u7F13\u5B58\u7684\u5168\u5C40\u5F00\u5173 |
| | | mybatis-plus.configuration.cache-enabled=true |
| | | # \u5EF6\u65F6\u52A0\u8F7D\u7684\u5F00\u5173 |
| | | mybatis-plus.configuration.lazyLoadingEnabled=true |
| | | # \u5F00\u542F\u7684\u8BDD\uFF0C\u5EF6\u65F6\u52A0\u8F7D\u4E00\u4E2A\u5C5E\u6027\u65F6\u4F1A\u52A0\u8F7D\u8BE5\u5BF9\u8C61\u5168\u90E8\u5C5E\u6027\uFF0C\u5426\u5219\u6309\u9700\u52A0\u8F7D\u5C5E\u6027 |
| | | mybatis-plus.configuration.multipleResultSetsEnabled=true |
| | | # \u6253\u5370sql\u8BED\u53E5,\u8C03\u8BD5\u7528 |
| | | mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl |
| | | |
| | | |
| | | ########################## beetl\u9ED8\u8BA4\u914D\u7F6E ########################### |
| | | #\u5F00\u59CB\u7ED3\u675F\u6807\u7B7E(yaml\u4E0D\u5141\u8BB8@\u5F00\u5934) |
| | | beetl.delimiter-statement-start=@ |
| | | beetl.delimiter-statement-end=null |
| | | #\u81EA\u5B9A\u4E49\u6807\u7B7E\u6587\u4EF6Root\u76EE\u5F55\u548C\u540E\u7F00 |
| | | beetl.resource-tagroot=common/tags |
| | | beetl.resource-tagsuffix=tag |
| | | #\u662F\u5426\u68C0\u6D4B\u6587\u4EF6\u53D8\u5316,\u5F00\u53D1\u7528true\u5408\u9002\uFF0C\u4F46\u7EBF\u4E0A\u8981\u6539\u4E3Afalse |
| | | beetl.resource-auto-check=true |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <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> |
| | | |
| | | <artifactId>guns-generator</artifactId> |
| | | <packaging>jar</packaging> |
| | | |
| | | <name>guns-generator</name> |
| | | <description>代码生成器</description> |
| | | |
| | | <parent> |
| | | <groupId>com.stylefeng</groupId> |
| | | <artifactId>guns-parent</artifactId> |
| | | <version>1.0.0</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.stylefeng</groupId> |
| | | <artifactId>guns-core</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.ibeetl</groupId> |
| | | <artifactId>beetl</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.baomidou</groupId> |
| | | <artifactId>mybatis-plus-generate</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | |
| | | </project> |
New file |
| | |
| | | package com.stylefeng.guns.generator.action; |
| | | |
| | | |
| | | import com.stylefeng.guns.generator.action.config.GunsGeneratorConfig; |
| | | |
| | | /** |
| | | * 代码生成器,可以生成实体,dao,service,controller,html,js |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/21 12:38 |
| | | */ |
| | | public class GunsCodeGenerator { |
| | | |
| | | public static void main(String[] args) { |
| | | |
| | | /** |
| | | * Mybatis-Plus的代码生成器: |
| | | * mp的代码生成器可以生成实体,mapper,mapper对应的xml,service |
| | | */ |
| | | GunsGeneratorConfig gunsGeneratorConfig = new GunsGeneratorConfig(); |
| | | gunsGeneratorConfig.doMpGeneration(); |
| | | |
| | | /** |
| | | * guns的生成器: |
| | | * guns的代码生成器可以生成controller,html页面,页面对应的js |
| | | */ |
| | | gunsGeneratorConfig.doGunsGeneration(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.action.config; |
| | | |
| | | import com.baomidou.mybatisplus.generator.AutoGenerator; |
| | | import com.baomidou.mybatisplus.generator.config.DataSourceConfig; |
| | | import com.baomidou.mybatisplus.generator.config.GlobalConfig; |
| | | import com.baomidou.mybatisplus.generator.config.PackageConfig; |
| | | import com.baomidou.mybatisplus.generator.config.StrategyConfig; |
| | | import com.baomidou.mybatisplus.generator.config.po.TableInfo; |
| | | import com.stylefeng.guns.core.util.FileUtil; |
| | | import com.stylefeng.guns.generator.engine.SimpleTemplateEngine; |
| | | import com.stylefeng.guns.generator.engine.base.GunsTemplateEngine; |
| | | import com.stylefeng.guns.generator.engine.config.ContextConfig; |
| | | import com.stylefeng.guns.generator.engine.config.SqlConfig; |
| | | |
| | | import java.io.File; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 代码生成的抽象配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-10-28-下午8:22 |
| | | */ |
| | | public abstract class AbstractGeneratorConfig { |
| | | |
| | | /** |
| | | * mybatis-plus代码生成器配置 |
| | | */ |
| | | GlobalConfig globalConfig = new GlobalConfig(); |
| | | |
| | | DataSourceConfig dataSourceConfig = new DataSourceConfig(); |
| | | |
| | | StrategyConfig strategyConfig = new StrategyConfig(); |
| | | |
| | | PackageConfig packageConfig = new PackageConfig(); |
| | | |
| | | TableInfo tableInfo = null; |
| | | |
| | | /** |
| | | * Guns代码生成器配置 |
| | | */ |
| | | ContextConfig contextConfig = new ContextConfig(); |
| | | |
| | | SqlConfig sqlConfig = new SqlConfig(); |
| | | |
| | | protected abstract void config(); |
| | | |
| | | public void init() { |
| | | config(); |
| | | |
| | | packageConfig.setService(contextConfig.getProPackage() + ".modular." + contextConfig.getModuleName() + ".service"); |
| | | packageConfig.setServiceImpl(contextConfig.getProPackage() + ".modular." + contextConfig.getModuleName() + ".service.impl"); |
| | | |
| | | //controller没用掉,生成之后会自动删掉 |
| | | packageConfig.setController("TTT"); |
| | | |
| | | if (!contextConfig.getEntitySwitch()) { |
| | | packageConfig.setEntity("TTT"); |
| | | } |
| | | |
| | | if (!contextConfig.getDaoSwitch()) { |
| | | packageConfig.setMapper("TTT"); |
| | | packageConfig.setXml("TTT"); |
| | | } |
| | | |
| | | if (!contextConfig.getServiceSwitch()) { |
| | | packageConfig.setService("TTT"); |
| | | packageConfig.setServiceImpl("TTT"); |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 删除不必要的代码 |
| | | */ |
| | | public void destory() { |
| | | String outputDir = globalConfig.getOutputDir() + "/TTT"; |
| | | FileUtil.deleteDir(new File(outputDir)); |
| | | } |
| | | |
| | | public AbstractGeneratorConfig() { |
| | | } |
| | | |
| | | public void doMpGeneration() { |
| | | init(); |
| | | AutoGenerator autoGenerator = new AutoGenerator(); |
| | | autoGenerator.setGlobalConfig(globalConfig); |
| | | autoGenerator.setDataSource(dataSourceConfig); |
| | | autoGenerator.setStrategy(strategyConfig); |
| | | autoGenerator.setPackageInfo(packageConfig); |
| | | autoGenerator.execute(); |
| | | destory(); |
| | | |
| | | //获取table信息,用于guns代码生成 |
| | | List<TableInfo> tableInfoList = autoGenerator.getConfig().getTableInfoList(); |
| | | if (tableInfoList != null && tableInfoList.size() > 0) { |
| | | this.tableInfo = tableInfoList.get(0); |
| | | } |
| | | } |
| | | |
| | | public void doGunsGeneration() { |
| | | GunsTemplateEngine GunsTemplateEngine = new SimpleTemplateEngine(); |
| | | GunsTemplateEngine.setContextConfig(contextConfig); |
| | | sqlConfig.setConnection(dataSourceConfig.getConn()); |
| | | GunsTemplateEngine.setSqlConfig(sqlConfig); |
| | | GunsTemplateEngine.setTableInfo(tableInfo); |
| | | GunsTemplateEngine.start(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.action.config; |
| | | |
| | | import com.baomidou.mybatisplus.generator.config.rules.DbType; |
| | | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; |
| | | |
| | | /** |
| | | * 默认的代码生成的配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-10-28-下午8:27 |
| | | */ |
| | | public class GunsGeneratorConfig extends AbstractGeneratorConfig { |
| | | |
| | | protected void globalConfig() { |
| | | globalConfig.setOutputDir("D:\\ttt");//写自己项目的绝对路径,注意具体到java目录 |
| | | globalConfig.setFileOverride(true); |
| | | globalConfig.setEnableCache(false); |
| | | globalConfig.setBaseResultMap(true); |
| | | globalConfig.setBaseColumnList(true); |
| | | globalConfig.setOpen(false); |
| | | globalConfig.setAuthor("stylefeng"); |
| | | } |
| | | |
| | | protected void dataSourceConfig() { |
| | | dataSourceConfig.setDbType(DbType.MYSQL); |
| | | dataSourceConfig.setDriverName("com.mysql.jdbc.Driver"); |
| | | dataSourceConfig.setUsername("root"); |
| | | dataSourceConfig.setPassword("root"); |
| | | dataSourceConfig.setUrl("jdbc:mysql://127.0.0.1:3306/guns?characterEncoding=utf8"); |
| | | } |
| | | |
| | | protected void strategyConfig() { |
| | | strategyConfig.setTablePrefix(new String[]{"sys_"});// 此处可以修改为您的表前缀 |
| | | strategyConfig.setNaming(NamingStrategy.underline_to_camel); |
| | | } |
| | | |
| | | protected void packageConfig() { |
| | | packageConfig.setParent(null); |
| | | packageConfig.setEntity("com.stylefeng.guns.admin.common.persistence.model"); |
| | | packageConfig.setMapper("com.stylefeng.guns.admin.common.persistence.dao"); |
| | | packageConfig.setXml("com.stylefeng.guns.admin.common.persistence.dao.mapping"); |
| | | } |
| | | |
| | | protected void contextConfig() { |
| | | contextConfig.setProPackage("com.stylefeng.guns.admin"); |
| | | contextConfig.setCoreBasePackage("com.stylefeng.guns.core"); |
| | | contextConfig.setBizChName("字典管理"); |
| | | contextConfig.setBizEnName("sysDict"); |
| | | contextConfig.setModuleName("system"); |
| | | contextConfig.setProjectPath("D:\\ideaSpace\\guns\\guns-admin");//写自己项目的绝对路径 |
| | | contextConfig.setEntityName("SysDict"); |
| | | sqlConfig.setParentMenuName(null);//这里写已有菜单的名称,当做父节点 |
| | | |
| | | /** |
| | | * mybatis-plus 生成器开关 |
| | | */ |
| | | contextConfig.setEntitySwitch(true); |
| | | contextConfig.setDaoSwitch(true); |
| | | contextConfig.setServiceSwitch(true); |
| | | |
| | | /** |
| | | * guns 生成器开关 |
| | | */ |
| | | contextConfig.setControllerSwitch(true); |
| | | contextConfig.setIndexPageSwitch(true); |
| | | contextConfig.setAddPageSwitch(true); |
| | | contextConfig.setEditPageSwitch(true); |
| | | contextConfig.setJsSwitch(true); |
| | | contextConfig.setInfoJsSwitch(true); |
| | | contextConfig.setSqlSwitch(true); |
| | | } |
| | | |
| | | @Override |
| | | protected void config() { |
| | | globalConfig(); |
| | | dataSourceConfig(); |
| | | strategyConfig(); |
| | | packageConfig(); |
| | | contextConfig(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.action.config; |
| | | |
| | | import com.baomidou.mybatisplus.generator.config.rules.DbType; |
| | | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; |
| | | import com.stylefeng.guns.core.support.StrKit; |
| | | import com.stylefeng.guns.core.util.ToolUtil; |
| | | import com.stylefeng.guns.generator.action.model.GenQo; |
| | | |
| | | import java.io.File; |
| | | |
| | | /** |
| | | * 默认的代码生成的配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-10-28-下午8:27 |
| | | */ |
| | | public class WebGeneratorConfig extends AbstractGeneratorConfig { |
| | | |
| | | private GenQo genQo; |
| | | |
| | | public WebGeneratorConfig(GenQo genQo) { |
| | | this.genQo = genQo; |
| | | } |
| | | |
| | | @Override |
| | | protected void config() { |
| | | /** |
| | | * 数据库配置 |
| | | */ |
| | | dataSourceConfig.setDbType(DbType.MYSQL); |
| | | dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver"); |
| | | dataSourceConfig.setUsername(genQo.getUserName()); |
| | | dataSourceConfig.setPassword(genQo.getPassword()); |
| | | dataSourceConfig.setUrl(genQo.getUrl()); |
| | | |
| | | /** |
| | | * 全局配置 |
| | | */ |
| | | globalConfig.setOutputDir(genQo.getProjectPath() + File.separator + "src" + File.separator + "main" + File.separator + "java"); |
| | | globalConfig.setFileOverride(true); |
| | | globalConfig.setEnableCache(false); |
| | | globalConfig.setBaseResultMap(true); |
| | | globalConfig.setBaseColumnList(true); |
| | | globalConfig.setOpen(false); |
| | | globalConfig.setAuthor(genQo.getAuthor()); |
| | | contextConfig.setProPackage(genQo.getProjectPackage()); |
| | | contextConfig.setCoreBasePackage(genQo.getCorePackage()); |
| | | |
| | | /** |
| | | * 生成策略 |
| | | */ |
| | | if (genQo.getIgnoreTabelPrefix() != null) { |
| | | strategyConfig.setTablePrefix(new String[]{genQo.getIgnoreTabelPrefix()}); |
| | | } |
| | | strategyConfig.setInclude(new String[]{genQo.getTableName()}); |
| | | strategyConfig.setNaming(NamingStrategy.underline_to_camel); |
| | | packageConfig.setParent(null); |
| | | packageConfig.setEntity(genQo.getProjectPackage() + ".modular.system.model"); |
| | | packageConfig.setMapper(genQo.getProjectPackage() + ".modular.system.dao"); |
| | | packageConfig.setXml(genQo.getProjectPackage() + ".modular.system.dao.mapping"); |
| | | |
| | | /** |
| | | * 业务代码配置 |
| | | */ |
| | | contextConfig.setBizChName(genQo.getBizName()); |
| | | contextConfig.setModuleName(genQo.getModuleName()); |
| | | contextConfig.setProjectPath(genQo.getProjectPath());//写自己项目的绝对路径 |
| | | if(ToolUtil.isEmpty(genQo.getIgnoreTabelPrefix())){ |
| | | String entityName = StrKit.toCamelCase(genQo.getTableName()); |
| | | contextConfig.setEntityName(StrKit.firstCharToUpperCase(entityName)); |
| | | contextConfig.setBizEnName(StrKit.firstCharToLowerCase(entityName)); |
| | | }else{ |
| | | String entiyName = StrKit.toCamelCase(StrKit.removePrefix(genQo.getTableName(), genQo.getIgnoreTabelPrefix())); |
| | | contextConfig.setEntityName(StrKit.firstCharToUpperCase(entiyName)); |
| | | contextConfig.setBizEnName(StrKit.firstCharToLowerCase(entiyName)); |
| | | } |
| | | sqlConfig.setParentMenuName(genQo.getParentMenuName());//这里写已有菜单的名称,当做父节点 |
| | | |
| | | /** |
| | | * mybatis-plus 生成器开关 |
| | | */ |
| | | contextConfig.setEntitySwitch(genQo.getEntitySwitch()); |
| | | contextConfig.setDaoSwitch(genQo.getDaoSwitch()); |
| | | contextConfig.setServiceSwitch(genQo.getServiceSwitch()); |
| | | |
| | | /** |
| | | * guns 生成器开关 |
| | | */ |
| | | contextConfig.setControllerSwitch(genQo.getControllerSwitch()); |
| | | contextConfig.setIndexPageSwitch(genQo.getIndexPageSwitch()); |
| | | contextConfig.setAddPageSwitch(genQo.getAddPageSwitch()); |
| | | contextConfig.setEditPageSwitch(genQo.getEditPageSwitch()); |
| | | contextConfig.setJsSwitch(genQo.getJsSwitch()); |
| | | contextConfig.setInfoJsSwitch(genQo.getInfoJsSwitch()); |
| | | contextConfig.setSqlSwitch(genQo.getSqlSwitch()); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.action.model; |
| | | |
| | | /** |
| | | * 代码生成的查询参数 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-11-30-下午2:05 |
| | | */ |
| | | public class GenQo { |
| | | |
| | | /** |
| | | * 数据库账号 |
| | | */ |
| | | private String userName; |
| | | |
| | | /** |
| | | * 数据库密码 |
| | | */ |
| | | private String password; |
| | | |
| | | /** |
| | | * 数据库url |
| | | */ |
| | | private String url; |
| | | |
| | | /** |
| | | * 项目地址 |
| | | */ |
| | | private String projectPath; |
| | | |
| | | /** |
| | | * 作者 |
| | | */ |
| | | private String author; |
| | | |
| | | /** |
| | | * 项目的包 |
| | | */ |
| | | private String projectPackage; |
| | | |
| | | /** |
| | | * 核心模块的包 |
| | | */ |
| | | private String corePackage; |
| | | |
| | | /** |
| | | * 表名称 |
| | | */ |
| | | private String tableName; |
| | | |
| | | /** |
| | | * 忽略的表前缀 |
| | | */ |
| | | private String ignoreTabelPrefix; |
| | | |
| | | /** |
| | | * 业务名称 |
| | | */ |
| | | private String bizName; |
| | | |
| | | /** |
| | | * 模块名 |
| | | */ |
| | | private String moduleName; |
| | | |
| | | /** |
| | | * 父级菜单名称 |
| | | */ |
| | | private String parentMenuName; |
| | | |
| | | /** |
| | | * 是否生成控制器代码开关 |
| | | */ |
| | | private Boolean controllerSwitch = false; |
| | | |
| | | /** |
| | | * 主页 |
| | | */ |
| | | private Boolean indexPageSwitch = false; |
| | | |
| | | /** |
| | | * 添加页面 |
| | | */ |
| | | private Boolean addPageSwitch = false; |
| | | |
| | | /** |
| | | * 编辑页面 |
| | | */ |
| | | private Boolean editPageSwitch = false; |
| | | |
| | | /** |
| | | * 主页的js |
| | | */ |
| | | private Boolean jsSwitch = false; |
| | | |
| | | /** |
| | | * 详情页面js |
| | | */ |
| | | private Boolean infoJsSwitch = false; |
| | | |
| | | /** |
| | | * dao的开关 |
| | | */ |
| | | private Boolean daoSwitch = false; |
| | | |
| | | /** |
| | | * service |
| | | */ |
| | | private Boolean serviceSwitch = false; |
| | | |
| | | /** |
| | | * 生成实体的开关 |
| | | */ |
| | | private Boolean entitySwitch = false; |
| | | |
| | | /** |
| | | * 生成sql的开关 |
| | | */ |
| | | private Boolean sqlSwitch = false; |
| | | |
| | | public String getUserName() { |
| | | return userName; |
| | | } |
| | | |
| | | public void setUserName(String userName) { |
| | | this.userName = userName; |
| | | } |
| | | |
| | | public String getPassword() { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) { |
| | | this.password = password; |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public String getProjectPath() { |
| | | return projectPath; |
| | | } |
| | | |
| | | public void setProjectPath(String projectPath) { |
| | | this.projectPath = projectPath; |
| | | } |
| | | |
| | | public String getAuthor() { |
| | | return author; |
| | | } |
| | | |
| | | public void setAuthor(String author) { |
| | | this.author = author; |
| | | } |
| | | |
| | | public String getCorePackage() { |
| | | return corePackage; |
| | | } |
| | | |
| | | public void setCorePackage(String corePackage) { |
| | | this.corePackage = corePackage; |
| | | } |
| | | |
| | | public String getProjectPackage() { |
| | | |
| | | return projectPackage; |
| | | } |
| | | |
| | | public void setProjectPackage(String projectPackage) { |
| | | this.projectPackage = projectPackage; |
| | | } |
| | | |
| | | public String getTableName() { |
| | | return tableName; |
| | | } |
| | | |
| | | public void setTableName(String tableName) { |
| | | this.tableName = tableName; |
| | | } |
| | | |
| | | public String getIgnoreTabelPrefix() { |
| | | return ignoreTabelPrefix; |
| | | } |
| | | |
| | | public void setIgnoreTabelPrefix(String ignoreTabelPrefix) { |
| | | this.ignoreTabelPrefix = ignoreTabelPrefix; |
| | | } |
| | | |
| | | public String getBizName() { |
| | | return bizName; |
| | | } |
| | | |
| | | public void setBizName(String bizName) { |
| | | this.bizName = bizName; |
| | | } |
| | | |
| | | public String getModuleName() { |
| | | return moduleName; |
| | | } |
| | | |
| | | public void setModuleName(String moduleName) { |
| | | this.moduleName = moduleName; |
| | | } |
| | | |
| | | public Boolean getControllerSwitch() { |
| | | return controllerSwitch; |
| | | } |
| | | |
| | | public void setControllerSwitch(Boolean controllerSwitch) { |
| | | this.controllerSwitch = controllerSwitch; |
| | | } |
| | | |
| | | public Boolean getIndexPageSwitch() { |
| | | return indexPageSwitch; |
| | | } |
| | | |
| | | public void setIndexPageSwitch(Boolean indexPageSwitch) { |
| | | this.indexPageSwitch = indexPageSwitch; |
| | | } |
| | | |
| | | public Boolean getAddPageSwitch() { |
| | | return addPageSwitch; |
| | | } |
| | | |
| | | public void setAddPageSwitch(Boolean addPageSwitch) { |
| | | this.addPageSwitch = addPageSwitch; |
| | | } |
| | | |
| | | public Boolean getEditPageSwitch() { |
| | | return editPageSwitch; |
| | | } |
| | | |
| | | public void setEditPageSwitch(Boolean editPageSwitch) { |
| | | this.editPageSwitch = editPageSwitch; |
| | | } |
| | | |
| | | public Boolean getJsSwitch() { |
| | | return jsSwitch; |
| | | } |
| | | |
| | | public void setJsSwitch(Boolean jsSwitch) { |
| | | this.jsSwitch = jsSwitch; |
| | | } |
| | | |
| | | public Boolean getInfoJsSwitch() { |
| | | return infoJsSwitch; |
| | | } |
| | | |
| | | public void setInfoJsSwitch(Boolean infoJsSwitch) { |
| | | this.infoJsSwitch = infoJsSwitch; |
| | | } |
| | | |
| | | public Boolean getDaoSwitch() { |
| | | return daoSwitch; |
| | | } |
| | | |
| | | public void setDaoSwitch(Boolean daoSwitch) { |
| | | this.daoSwitch = daoSwitch; |
| | | } |
| | | |
| | | public Boolean getServiceSwitch() { |
| | | return serviceSwitch; |
| | | } |
| | | |
| | | public void setServiceSwitch(Boolean serviceSwitch) { |
| | | this.serviceSwitch = serviceSwitch; |
| | | } |
| | | |
| | | public Boolean getEntitySwitch() { |
| | | return entitySwitch; |
| | | } |
| | | |
| | | public void setEntitySwitch(Boolean entitySwitch) { |
| | | this.entitySwitch = entitySwitch; |
| | | } |
| | | |
| | | public Boolean getSqlSwitch() { |
| | | return sqlSwitch; |
| | | } |
| | | |
| | | public void setSqlSwitch(Boolean sqlSwitch) { |
| | | this.sqlSwitch = sqlSwitch; |
| | | } |
| | | |
| | | public String getParentMenuName() { |
| | | return parentMenuName; |
| | | } |
| | | |
| | | public void setParentMenuName(String parentMenuName) { |
| | | this.parentMenuName = parentMenuName; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine; |
| | | |
| | | |
| | | import com.stylefeng.guns.core.util.ToolUtil; |
| | | import com.stylefeng.guns.generator.engine.base.GunsTemplateEngine; |
| | | |
| | | /** |
| | | * 通用的模板生成引擎 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-09 20:32 |
| | | */ |
| | | public class SimpleTemplateEngine extends GunsTemplateEngine { |
| | | |
| | | @Override |
| | | protected void generatePageEditHtml() { |
| | | String path = ToolUtil.format(super.getContextConfig().getProjectPath() + getPageConfig().getPageEditPathTemplate(), |
| | | super.getContextConfig().getBizEnName(), super.getContextConfig().getBizEnName()); |
| | | generateFile(super.getContextConfig().getTemplatePrefixPath() + "/page_edit.html.btl", path); |
| | | System.out.println("生成编辑页面成功!"); |
| | | } |
| | | |
| | | @Override |
| | | protected void generatePageAddHtml() { |
| | | String path = ToolUtil.format(super.getContextConfig().getProjectPath() + getPageConfig().getPageAddPathTemplate(), |
| | | super.getContextConfig().getBizEnName(), super.getContextConfig().getBizEnName()); |
| | | generateFile(super.getContextConfig().getTemplatePrefixPath() + "/page_add.html.btl", path); |
| | | System.out.println("生成添加页面成功!"); |
| | | } |
| | | |
| | | @Override |
| | | protected void generatePageInfoJs() { |
| | | String path = ToolUtil.format(super.getContextConfig().getProjectPath() + getPageConfig().getPageInfoJsPathTemplate(), |
| | | super.getContextConfig().getBizEnName(), super.getContextConfig().getBizEnName()); |
| | | generateFile(super.getContextConfig().getTemplatePrefixPath() + "/page_info.js.btl", path); |
| | | System.out.println("生成页面详情js成功!"); |
| | | } |
| | | |
| | | @Override |
| | | protected void generatePageJs() { |
| | | String path = ToolUtil.format(super.getContextConfig().getProjectPath() + getPageConfig().getPageJsPathTemplate(), |
| | | super.getContextConfig().getBizEnName(), super.getContextConfig().getBizEnName()); |
| | | generateFile(super.getContextConfig().getTemplatePrefixPath() + "/page.js.btl", path); |
| | | System.out.println("生成页面js成功!"); |
| | | } |
| | | |
| | | @Override |
| | | protected void generatePageHtml() { |
| | | String path = ToolUtil.format(super.getContextConfig().getProjectPath() + getPageConfig().getPagePathTemplate(), |
| | | super.getContextConfig().getBizEnName(), super.getContextConfig().getBizEnName()); |
| | | generateFile(super.getContextConfig().getTemplatePrefixPath() + "/page.html.btl", path); |
| | | System.out.println("生成页面成功!"); |
| | | } |
| | | |
| | | @Override |
| | | protected void generateController() { |
| | | String controllerPath = ToolUtil.format(super.getContextConfig().getProjectPath() + super.getControllerConfig().getControllerPathTemplate(), |
| | | ToolUtil.firstLetterToUpper(super.getContextConfig().getBizEnName())); |
| | | generateFile(super.getContextConfig().getTemplatePrefixPath() + "/Controller.java.btl", controllerPath); |
| | | System.out.println("生成控制器成功!"); |
| | | } |
| | | |
| | | @Override |
| | | protected void generateSqls() { |
| | | String path = ToolUtil.format(super.getContextConfig().getProjectPath() + super.sqlConfig.getSqlPathTemplate(), |
| | | ToolUtil.firstLetterToUpper(super.getContextConfig().getBizEnName())); |
| | | generateFile(super.getContextConfig().getTemplatePrefixPath() + "/menu_sql.sql.btl", path); |
| | | System.out.println("生成sql成功!"); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.base; |
| | | |
| | | import com.baomidou.mybatisplus.generator.config.po.TableInfo; |
| | | import com.stylefeng.guns.generator.engine.config.*; |
| | | |
| | | /** |
| | | * 模板生成父类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-08 20:17 |
| | | */ |
| | | public class AbstractTemplateEngine { |
| | | |
| | | protected ContextConfig contextConfig; //全局配置 |
| | | protected ControllerConfig controllerConfig; //控制器的配置 |
| | | protected PageConfig pageConfig; //页面的控制器 |
| | | protected DaoConfig daoConfig; //Dao配置 |
| | | protected ServiceConfig serviceConfig; //Service配置 |
| | | protected SqlConfig sqlConfig; //sql配置 |
| | | protected TableInfo tableInfo; //表的信息 |
| | | |
| | | public void initConfig() { |
| | | if (this.contextConfig == null) { |
| | | this.contextConfig = new ContextConfig(); |
| | | } |
| | | if (this.controllerConfig == null) { |
| | | this.controllerConfig = new ControllerConfig(); |
| | | } |
| | | if (this.pageConfig == null) { |
| | | this.pageConfig = new PageConfig(); |
| | | } |
| | | if (this.daoConfig == null) { |
| | | this.daoConfig = new DaoConfig(); |
| | | } |
| | | if (this.serviceConfig == null) { |
| | | this.serviceConfig = new ServiceConfig(); |
| | | } |
| | | if (this.sqlConfig == null) { |
| | | this.sqlConfig = new SqlConfig(); |
| | | } |
| | | this.contextConfig.init(); |
| | | |
| | | this.controllerConfig.setContextConfig(this.contextConfig); |
| | | this.controllerConfig.init(); |
| | | |
| | | this.serviceConfig.setContextConfig(this.contextConfig); |
| | | this.serviceConfig.init(); |
| | | |
| | | this.daoConfig.setContextConfig(this.contextConfig); |
| | | this.daoConfig.init(); |
| | | |
| | | this.pageConfig.setContextConfig(this.contextConfig); |
| | | this.pageConfig.init(); |
| | | |
| | | this.sqlConfig.setContextConfig(this.contextConfig); |
| | | this.sqlConfig.init(); |
| | | } |
| | | |
| | | public PageConfig getPageConfig() { |
| | | return pageConfig; |
| | | } |
| | | |
| | | public void setPageConfig(PageConfig pageConfig) { |
| | | this.pageConfig = pageConfig; |
| | | } |
| | | |
| | | public ContextConfig getContextConfig() { |
| | | return contextConfig; |
| | | } |
| | | |
| | | public void setContextConfig(ContextConfig contextConfig) { |
| | | this.contextConfig = contextConfig; |
| | | } |
| | | |
| | | public ControllerConfig getControllerConfig() { |
| | | return controllerConfig; |
| | | } |
| | | |
| | | public void setControllerConfig(ControllerConfig controllerConfig) { |
| | | this.controllerConfig = controllerConfig; |
| | | } |
| | | |
| | | public DaoConfig getDaoConfig() { |
| | | return daoConfig; |
| | | } |
| | | |
| | | public void setDaoConfig(DaoConfig daoConfig) { |
| | | this.daoConfig = daoConfig; |
| | | } |
| | | |
| | | public ServiceConfig getServiceConfig() { |
| | | return serviceConfig; |
| | | } |
| | | |
| | | public void setServiceConfig(ServiceConfig serviceConfig) { |
| | | this.serviceConfig = serviceConfig; |
| | | } |
| | | |
| | | public SqlConfig getSqlConfig() { |
| | | return sqlConfig; |
| | | } |
| | | |
| | | public void setSqlConfig(SqlConfig sqlConfig) { |
| | | this.sqlConfig = sqlConfig; |
| | | } |
| | | |
| | | public TableInfo getTableInfo() { |
| | | return tableInfo; |
| | | } |
| | | |
| | | public void setTableInfo(TableInfo tableInfo) { |
| | | this.tableInfo = tableInfo; |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.base; |
| | | |
| | | import com.stylefeng.guns.core.util.ToolUtil; |
| | | import com.sun.javafx.PlatformUtil; |
| | | import org.beetl.core.Configuration; |
| | | import org.beetl.core.GroupTemplate; |
| | | import org.beetl.core.Template; |
| | | import org.beetl.core.resource.ClasspathResourceLoader; |
| | | |
| | | import java.io.File; |
| | | import java.io.FileNotFoundException; |
| | | import java.io.FileOutputStream; |
| | | import java.io.IOException; |
| | | import java.util.Properties; |
| | | |
| | | /** |
| | | * ADI项目模板生成 引擎 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-07 22:15 |
| | | */ |
| | | public abstract class GunsTemplateEngine extends AbstractTemplateEngine { |
| | | |
| | | private GroupTemplate groupTemplate; |
| | | |
| | | public GunsTemplateEngine() { |
| | | initBeetlEngine(); |
| | | } |
| | | |
| | | protected void initBeetlEngine() { |
| | | Properties properties = new Properties(); |
| | | properties.put("RESOURCE.root", ""); |
| | | properties.put("DELIMITER_STATEMENT_START", "<%"); |
| | | properties.put("DELIMITER_STATEMENT_END", "%>"); |
| | | properties.put("HTML_TAG_FLAG", "##"); |
| | | Configuration cfg = null; |
| | | try { |
| | | cfg = new Configuration(properties); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader(); |
| | | groupTemplate = new GroupTemplate(resourceLoader, cfg); |
| | | groupTemplate.registerFunctionPackage("tool", new ToolUtil()); |
| | | } |
| | | |
| | | protected void configTemplate(Template template) { |
| | | template.binding("controller", super.controllerConfig); |
| | | template.binding("context", super.contextConfig); |
| | | template.binding("dao", super.daoConfig); |
| | | template.binding("service", super.serviceConfig); |
| | | template.binding("sqls", super.sqlConfig); |
| | | template.binding("table", super.tableInfo); |
| | | } |
| | | |
| | | protected void generateFile(String template, String filePath) { |
| | | Template pageTemplate = groupTemplate.getTemplate(template); |
| | | configTemplate(pageTemplate); |
| | | if (PlatformUtil.isWindows()) { |
| | | filePath = filePath.replaceAll("/+|\\\\+", "\\\\"); |
| | | } else { |
| | | filePath = filePath.replaceAll("/+|\\\\+", "/"); |
| | | } |
| | | File file = new File(filePath); |
| | | File parentFile = file.getParentFile(); |
| | | if (!parentFile.exists()) { |
| | | parentFile.mkdirs(); |
| | | } |
| | | FileOutputStream fileOutputStream = null; |
| | | try { |
| | | fileOutputStream = new FileOutputStream(file); |
| | | pageTemplate.renderTo(fileOutputStream); |
| | | } catch (FileNotFoundException e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | fileOutputStream.close(); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public void start() { |
| | | //配置之间的相互依赖 |
| | | super.initConfig(); |
| | | |
| | | //生成模板 |
| | | if (super.contextConfig.getControllerSwitch()) { |
| | | generateController(); |
| | | } |
| | | if (super.contextConfig.getIndexPageSwitch()) { |
| | | generatePageHtml(); |
| | | } |
| | | if (super.contextConfig.getAddPageSwitch()) { |
| | | generatePageAddHtml(); |
| | | } |
| | | if (super.contextConfig.getEditPageSwitch()) { |
| | | generatePageEditHtml(); |
| | | } |
| | | if (super.contextConfig.getJsSwitch()) { |
| | | generatePageJs(); |
| | | } |
| | | if (super.contextConfig.getInfoJsSwitch()) { |
| | | generatePageInfoJs(); |
| | | } |
| | | if (super.contextConfig.getSqlSwitch()) { |
| | | generateSqls(); |
| | | } |
| | | } |
| | | |
| | | protected abstract void generatePageEditHtml(); |
| | | |
| | | protected abstract void generatePageAddHtml(); |
| | | |
| | | protected abstract void generatePageInfoJs(); |
| | | |
| | | protected abstract void generatePageJs(); |
| | | |
| | | protected abstract void generatePageHtml(); |
| | | |
| | | protected abstract void generateController(); |
| | | |
| | | protected abstract void generateSqls(); |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.config; |
| | | |
| | | |
| | | import com.stylefeng.guns.core.util.ToolUtil; |
| | | |
| | | /** |
| | | * 全局配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-08 20:21 |
| | | */ |
| | | public class ContextConfig { |
| | | |
| | | private String templatePrefixPath = "gunsTemplate/advanced"; |
| | | private String projectPath = "D:\\ideaSpace\\guns";//模板输出的项目目录 |
| | | private String bizChName; //业务名称 |
| | | private String bizEnName; //业务英文名称 |
| | | private String bizEnBigName;//业务英文名称(大写) |
| | | private String moduleName = "system"; //模块名称 |
| | | |
| | | private String proPackage = "com.stylefeng.guns.admin"; |
| | | private String coreBasePackage = "com.stylefeng.guns.core"; |
| | | private String modelPackageName = "com.stylefeng.guns.modular.system.model"; //model的包名 |
| | | private String modelMapperPackageName = "com.stylefeng.guns.modular.system.dao"; //model的dao |
| | | private String entityName; //实体的名称 |
| | | |
| | | private Boolean controllerSwitch = true; //是否生成控制器代码开关 |
| | | private Boolean indexPageSwitch = true; //主页 |
| | | private Boolean addPageSwitch = true; //添加页面 |
| | | private Boolean editPageSwitch = true; //编辑页面 |
| | | private Boolean jsSwitch = true; //js |
| | | private Boolean infoJsSwitch = true; //详情页面js |
| | | private Boolean daoSwitch = true; //dao |
| | | private Boolean serviceSwitch = true; //service |
| | | private Boolean entitySwitch = true; //生成实体的开关 |
| | | private Boolean sqlSwitch = true; //生成sql的开关 |
| | | |
| | | public void init() { |
| | | if (entityName == null) { |
| | | entityName = bizEnBigName; |
| | | } |
| | | modelPackageName = proPackage + "." + "modular.system.model"; |
| | | modelMapperPackageName = proPackage + "." + "modular.system.dao"; |
| | | } |
| | | |
| | | public String getBizEnBigName() { |
| | | return bizEnBigName; |
| | | } |
| | | |
| | | public void setBizEnBigName(String bizEnBigName) { |
| | | this.bizEnBigName = bizEnBigName; |
| | | } |
| | | |
| | | public String getBizChName() { |
| | | return bizChName; |
| | | } |
| | | |
| | | public void setBizChName(String bizChName) { |
| | | this.bizChName = bizChName; |
| | | } |
| | | |
| | | public String getBizEnName() { |
| | | return bizEnName; |
| | | } |
| | | |
| | | public void setBizEnName(String bizEnName) { |
| | | this.bizEnName = bizEnName; |
| | | this.bizEnBigName = ToolUtil.firstLetterToUpper(this.bizEnName); |
| | | } |
| | | |
| | | public String getProjectPath() { |
| | | return projectPath; |
| | | } |
| | | |
| | | public void setProjectPath(String projectPath) { |
| | | this.projectPath = projectPath; |
| | | } |
| | | |
| | | public String getModuleName() { |
| | | return moduleName; |
| | | } |
| | | |
| | | public void setModuleName(String moduleName) { |
| | | this.moduleName = moduleName; |
| | | } |
| | | |
| | | public Boolean getControllerSwitch() { |
| | | return controllerSwitch; |
| | | } |
| | | |
| | | public void setControllerSwitch(Boolean controllerSwitch) { |
| | | this.controllerSwitch = controllerSwitch; |
| | | } |
| | | |
| | | public Boolean getIndexPageSwitch() { |
| | | return indexPageSwitch; |
| | | } |
| | | |
| | | public void setIndexPageSwitch(Boolean indexPageSwitch) { |
| | | this.indexPageSwitch = indexPageSwitch; |
| | | } |
| | | |
| | | public Boolean getAddPageSwitch() { |
| | | return addPageSwitch; |
| | | } |
| | | |
| | | public void setAddPageSwitch(Boolean addPageSwitch) { |
| | | this.addPageSwitch = addPageSwitch; |
| | | } |
| | | |
| | | public Boolean getEditPageSwitch() { |
| | | return editPageSwitch; |
| | | } |
| | | |
| | | public void setEditPageSwitch(Boolean editPageSwitch) { |
| | | this.editPageSwitch = editPageSwitch; |
| | | } |
| | | |
| | | public Boolean getJsSwitch() { |
| | | return jsSwitch; |
| | | } |
| | | |
| | | public void setJsSwitch(Boolean jsSwitch) { |
| | | this.jsSwitch = jsSwitch; |
| | | } |
| | | |
| | | public Boolean getInfoJsSwitch() { |
| | | return infoJsSwitch; |
| | | } |
| | | |
| | | public void setInfoJsSwitch(Boolean infoJsSwitch) { |
| | | this.infoJsSwitch = infoJsSwitch; |
| | | } |
| | | |
| | | public Boolean getDaoSwitch() { |
| | | return daoSwitch; |
| | | } |
| | | |
| | | public void setDaoSwitch(Boolean daoSwitch) { |
| | | this.daoSwitch = daoSwitch; |
| | | } |
| | | |
| | | public Boolean getServiceSwitch() { |
| | | return serviceSwitch; |
| | | } |
| | | |
| | | public void setServiceSwitch(Boolean serviceSwitch) { |
| | | this.serviceSwitch = serviceSwitch; |
| | | } |
| | | |
| | | public String getTemplatePrefixPath() { |
| | | return templatePrefixPath; |
| | | } |
| | | |
| | | public void setTemplatePrefixPath(String templatePrefixPath) { |
| | | this.templatePrefixPath = templatePrefixPath; |
| | | } |
| | | |
| | | public String getModelPackageName() { |
| | | return modelPackageName; |
| | | } |
| | | |
| | | public void setModelPackageName(String modelPackageName) { |
| | | this.modelPackageName = modelPackageName; |
| | | } |
| | | |
| | | public String getEntityName() { |
| | | return entityName; |
| | | } |
| | | |
| | | public void setEntityName(String entityName) { |
| | | this.entityName = entityName; |
| | | } |
| | | |
| | | public String getModelMapperPackageName() { |
| | | return modelMapperPackageName; |
| | | } |
| | | |
| | | public void setModelMapperPackageName(String modelMapperPackageName) { |
| | | this.modelMapperPackageName = modelMapperPackageName; |
| | | } |
| | | |
| | | public Boolean getEntitySwitch() { |
| | | return entitySwitch; |
| | | } |
| | | |
| | | public void setEntitySwitch(Boolean entitySwitch) { |
| | | this.entitySwitch = entitySwitch; |
| | | } |
| | | |
| | | public Boolean getSqlSwitch() { |
| | | return sqlSwitch; |
| | | } |
| | | |
| | | public void setSqlSwitch(Boolean sqlSwitch) { |
| | | this.sqlSwitch = sqlSwitch; |
| | | } |
| | | |
| | | public String getProPackage() { |
| | | return proPackage; |
| | | } |
| | | |
| | | public void setProPackage(String proPackage) { |
| | | this.proPackage = proPackage; |
| | | } |
| | | |
| | | public String getCoreBasePackage() { |
| | | return coreBasePackage; |
| | | } |
| | | |
| | | public void setCoreBasePackage(String coreBasePackage) { |
| | | this.coreBasePackage = coreBasePackage; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.config; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 控制器模板生成的配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-07 22:12 |
| | | */ |
| | | public class ControllerConfig { |
| | | |
| | | private ContextConfig contextConfig; |
| | | |
| | | private String controllerPathTemplate; |
| | | private String packageName;//包名称 |
| | | private List<String> imports;//所引入的包 |
| | | |
| | | public void init() { |
| | | ArrayList<String> imports = new ArrayList<>(); |
| | | imports.add(contextConfig.getCoreBasePackage() + ".base.controller.BaseController"); |
| | | imports.add("org.springframework.stereotype.Controller"); |
| | | imports.add("org.springframework.web.bind.annotation.RequestMapping"); |
| | | imports.add("org.springframework.web.bind.annotation.ResponseBody"); |
| | | imports.add("org.springframework.ui.Model"); |
| | | imports.add("org.springframework.web.bind.annotation.PathVariable"); |
| | | imports.add("org.springframework.beans.factory.annotation.Autowired"); |
| | | imports.add(contextConfig.getProPackage() + ".core.log.LogObjectHolder"); |
| | | imports.add("org.springframework.web.bind.annotation.RequestParam"); |
| | | imports.add(contextConfig.getModelPackageName() + "." + contextConfig.getEntityName()); |
| | | imports.add(contextConfig.getProPackage() + ".modular." + contextConfig.getModuleName() + ".service" + ".I" + contextConfig.getEntityName() + "Service"); |
| | | this.imports = imports; |
| | | this.packageName = contextConfig.getProPackage() + ".modular." + contextConfig.getModuleName() + ".controller"; |
| | | this.controllerPathTemplate = "\\src\\main\\java\\"+contextConfig.getProPackage().replaceAll("\\.","\\\\")+"\\modular\\" + contextConfig.getModuleName() + "\\controller\\{}Controller.java"; |
| | | } |
| | | |
| | | public String getPackageName() { |
| | | return packageName; |
| | | } |
| | | |
| | | public void setPackageName(String packageName) { |
| | | this.packageName = packageName; |
| | | } |
| | | |
| | | public List<String> getImports() { |
| | | return imports; |
| | | } |
| | | |
| | | public void setImports(List<String> imports) { |
| | | this.imports = imports; |
| | | } |
| | | |
| | | public String getControllerPathTemplate() { |
| | | return controllerPathTemplate; |
| | | } |
| | | |
| | | public void setControllerPathTemplate(String controllerPathTemplate) { |
| | | this.controllerPathTemplate = controllerPathTemplate; |
| | | } |
| | | |
| | | public ContextConfig getContextConfig() { |
| | | return contextConfig; |
| | | } |
| | | |
| | | public void setContextConfig(ContextConfig contextConfig) { |
| | | this.contextConfig = contextConfig; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.config; |
| | | |
| | | /** |
| | | * Dao模板生成的配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-07 22:12 |
| | | */ |
| | | public class DaoConfig { |
| | | |
| | | private ContextConfig contextConfig; |
| | | |
| | | private String daoPathTemplate; |
| | | private String xmlPathTemplate; |
| | | |
| | | private String packageName; |
| | | |
| | | public void init() { |
| | | this.daoPathTemplate = "\\src\\main\\java\\" + contextConfig.getProPackage().replaceAll("\\.", "\\\\") + "\\modular\\" + contextConfig.getModuleName() + "\\dao\\{}Dao.java"; |
| | | this.xmlPathTemplate = "\\src\\main\\java\\" + contextConfig.getProPackage().replaceAll("\\.", "\\\\") + "\\modular\\" + contextConfig.getModuleName() + "\\dao\\mapping\\{}Dao.xml"; |
| | | this.packageName = contextConfig.getProPackage() + ".modular." + contextConfig.getModuleName() + ".dao"; |
| | | } |
| | | |
| | | public String getPackageName() { |
| | | return packageName; |
| | | } |
| | | |
| | | public void setPackageName(String packageName) { |
| | | this.packageName = packageName; |
| | | } |
| | | |
| | | public String getDaoPathTemplate() { |
| | | return daoPathTemplate; |
| | | } |
| | | |
| | | public void setDaoPathTemplate(String daoPathTemplate) { |
| | | this.daoPathTemplate = daoPathTemplate; |
| | | } |
| | | |
| | | public String getXmlPathTemplate() { |
| | | return xmlPathTemplate; |
| | | } |
| | | |
| | | public void setXmlPathTemplate(String xmlPathTemplate) { |
| | | this.xmlPathTemplate = xmlPathTemplate; |
| | | } |
| | | |
| | | public ContextConfig getContextConfig() { |
| | | return contextConfig; |
| | | } |
| | | |
| | | public void setContextConfig(ContextConfig contextConfig) { |
| | | this.contextConfig = contextConfig; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.config; |
| | | |
| | | import com.baomidou.mybatisplus.activerecord.Model; |
| | | import com.baomidou.mybatisplus.annotations.TableId; |
| | | import com.baomidou.mybatisplus.enums.IdType; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * <p> |
| | | * 菜单表 |
| | | * </p> |
| | | * |
| | | * @author stylefeng |
| | | * @since 2017-07-11 |
| | | */ |
| | | public class Menu extends Model<Menu> { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * 主键id |
| | | */ |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | /** |
| | | * 菜单编号 |
| | | */ |
| | | private String code; |
| | | /** |
| | | * 菜单父编号 |
| | | */ |
| | | private String pcode; |
| | | /** |
| | | * 当前菜单的所有父菜单编号 |
| | | */ |
| | | private String pcodes; |
| | | /** |
| | | * 菜单名称 |
| | | */ |
| | | private String name; |
| | | /** |
| | | * 菜单图标 |
| | | */ |
| | | private String icon; |
| | | /** |
| | | * url地址 |
| | | */ |
| | | private String url; |
| | | /** |
| | | * 菜单排序号 |
| | | */ |
| | | private Integer num; |
| | | /** |
| | | * 菜单层级 |
| | | */ |
| | | private Integer levels; |
| | | /** |
| | | * 是否是菜单(1:是 0:不是) |
| | | */ |
| | | private Integer ismenu; |
| | | /** |
| | | * 备注 |
| | | */ |
| | | private String tips; |
| | | /** |
| | | * 菜单状态 : 1:启用 0:不启用 |
| | | */ |
| | | private Integer status; |
| | | /** |
| | | * 是否打开: 1:打开 0:不打开 |
| | | */ |
| | | private Integer isopen; |
| | | |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public String getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(String code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getPcode() { |
| | | return pcode; |
| | | } |
| | | |
| | | public void setPcode(String pcode) { |
| | | this.pcode = pcode; |
| | | } |
| | | |
| | | public String getPcodes() { |
| | | return pcodes; |
| | | } |
| | | |
| | | public void setPcodes(String pcodes) { |
| | | this.pcodes = pcodes; |
| | | } |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public String getIcon() { |
| | | return icon; |
| | | } |
| | | |
| | | public void setIcon(String icon) { |
| | | this.icon = icon; |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public Integer getNum() { |
| | | return num; |
| | | } |
| | | |
| | | public void setNum(Integer num) { |
| | | this.num = num; |
| | | } |
| | | |
| | | public Integer getLevels() { |
| | | return levels; |
| | | } |
| | | |
| | | public void setLevels(Integer levels) { |
| | | this.levels = levels; |
| | | } |
| | | |
| | | public Integer getIsmenu() { |
| | | return ismenu; |
| | | } |
| | | |
| | | public void setIsmenu(Integer ismenu) { |
| | | this.ismenu = ismenu; |
| | | } |
| | | |
| | | public String getTips() { |
| | | return tips; |
| | | } |
| | | |
| | | public void setTips(String tips) { |
| | | this.tips = tips; |
| | | } |
| | | |
| | | public Integer getStatus() { |
| | | return status; |
| | | } |
| | | |
| | | public void setStatus(Integer status) { |
| | | this.status = status; |
| | | } |
| | | |
| | | public Integer getIsopen() { |
| | | return isopen; |
| | | } |
| | | |
| | | public void setIsopen(Integer isopen) { |
| | | this.isopen = isopen; |
| | | } |
| | | |
| | | @Override |
| | | protected Serializable pkVal() { |
| | | return this.id; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "Menu{" + |
| | | "id=" + id + |
| | | ", code=" + code + |
| | | ", pcode=" + pcode + |
| | | ", pcodes=" + pcodes + |
| | | ", name=" + name + |
| | | ", icon=" + icon + |
| | | ", url=" + url + |
| | | ", num=" + num + |
| | | ", levels=" + levels + |
| | | ", ismenu=" + ismenu + |
| | | ", tips=" + tips + |
| | | ", status=" + status + |
| | | ", isopen=" + isopen + |
| | | "}"; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.config; |
| | | |
| | | /** |
| | | * 页面 模板生成的配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-07 22:12 |
| | | */ |
| | | public class PageConfig { |
| | | |
| | | private ContextConfig contextConfig; |
| | | |
| | | private String pagePathTemplate; |
| | | private String pageAddPathTemplate; |
| | | private String pageEditPathTemplate; |
| | | private String pageJsPathTemplate; |
| | | private String pageInfoJsPathTemplate; |
| | | |
| | | public void init() { |
| | | pagePathTemplate = "\\src\\main\\webapp\\WEB-INF\\view\\" + contextConfig.getModuleName() + "\\{}\\{}.html"; |
| | | pageAddPathTemplate = "\\src\\main\\webapp\\WEB-INF\\view\\" + contextConfig.getModuleName() + "\\{}\\{}_add.html"; |
| | | pageEditPathTemplate = "\\src\\main\\webapp\\WEB-INF\\view\\" + contextConfig.getModuleName() + "\\{}\\{}_edit.html"; |
| | | pageJsPathTemplate = "\\src\\main\\webapp\\static\\modular\\" + contextConfig.getModuleName() + "\\{}\\{}.js"; |
| | | pageInfoJsPathTemplate = "\\src\\main\\webapp\\static\\modular\\" + contextConfig.getModuleName() + "\\{}\\{}_info.js"; |
| | | } |
| | | |
| | | public String getPagePathTemplate() { |
| | | return pagePathTemplate; |
| | | } |
| | | |
| | | public void setPagePathTemplate(String pagePathTemplate) { |
| | | this.pagePathTemplate = pagePathTemplate; |
| | | } |
| | | |
| | | public String getPageJsPathTemplate() { |
| | | return pageJsPathTemplate; |
| | | } |
| | | |
| | | public void setPageJsPathTemplate(String pageJsPathTemplate) { |
| | | this.pageJsPathTemplate = pageJsPathTemplate; |
| | | } |
| | | |
| | | public String getPageAddPathTemplate() { |
| | | return pageAddPathTemplate; |
| | | } |
| | | |
| | | public void setPageAddPathTemplate(String pageAddPathTemplate) { |
| | | this.pageAddPathTemplate = pageAddPathTemplate; |
| | | } |
| | | |
| | | public String getPageEditPathTemplate() { |
| | | return pageEditPathTemplate; |
| | | } |
| | | |
| | | public void setPageEditPathTemplate(String pageEditPathTemplate) { |
| | | this.pageEditPathTemplate = pageEditPathTemplate; |
| | | } |
| | | |
| | | public String getPageInfoJsPathTemplate() { |
| | | return pageInfoJsPathTemplate; |
| | | } |
| | | |
| | | public void setPageInfoJsPathTemplate(String pageInfoJsPathTemplate) { |
| | | this.pageInfoJsPathTemplate = pageInfoJsPathTemplate; |
| | | } |
| | | |
| | | public ContextConfig getContextConfig() { |
| | | return contextConfig; |
| | | } |
| | | |
| | | public void setContextConfig(ContextConfig contextConfig) { |
| | | this.contextConfig = contextConfig; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.config; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * Service模板生成的配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-07 22:12 |
| | | */ |
| | | public class ServiceConfig { |
| | | |
| | | private ContextConfig contextConfig; |
| | | |
| | | private String servicePathTemplate; |
| | | private String serviceImplPathTemplate; |
| | | |
| | | private String packageName; |
| | | |
| | | private List<String> serviceInterfaceImports; |
| | | private List<String> serviceImplImports; |
| | | |
| | | public void init() { |
| | | ArrayList<String> imports = new ArrayList<>(); |
| | | imports.add("org.springframework.stereotype.Service"); |
| | | imports.add("com.baomidou.mybatisplus.service.impl.ServiceImpl"); |
| | | imports.add(contextConfig.getModelPackageName() + "." + contextConfig.getEntityName()); |
| | | imports.add(contextConfig.getModelMapperPackageName() + "." + contextConfig.getEntityName() + "Mapper"); |
| | | imports.add(contextConfig.getProPackage() + ".modular." + contextConfig.getModuleName() + ".service.I" + contextConfig.getBizEnBigName() + "Service"); |
| | | this.serviceImplImports = imports; |
| | | |
| | | ArrayList<String> interfaceImports = new ArrayList<>(); |
| | | interfaceImports.add("com.baomidou.mybatisplus.service.IService"); |
| | | interfaceImports.add(contextConfig.getModelPackageName() + "." + contextConfig.getEntityName()); |
| | | this.serviceInterfaceImports = interfaceImports; |
| | | |
| | | this.servicePathTemplate = "\\src\\main\\java\\" + contextConfig.getProPackage().replaceAll("\\.", "\\\\") + "\\modular\\" + contextConfig.getModuleName() + "\\service\\I{}Service.java"; |
| | | this.serviceImplPathTemplate = "\\src\\main\\java\\" + contextConfig.getProPackage().replaceAll("\\.", "\\\\") + "\\modular\\" + contextConfig.getModuleName() + "\\service\\impl\\{}ServiceImpl.java"; |
| | | this.packageName = contextConfig.getProPackage() + ".modular." + contextConfig.getModuleName() + ".service"; |
| | | } |
| | | |
| | | |
| | | public String getServicePathTemplate() { |
| | | return servicePathTemplate; |
| | | } |
| | | |
| | | public void setServicePathTemplate(String servicePathTemplate) { |
| | | this.servicePathTemplate = servicePathTemplate; |
| | | } |
| | | |
| | | public String getPackageName() { |
| | | return packageName; |
| | | } |
| | | |
| | | public void setPackageName(String packageName) { |
| | | this.packageName = packageName; |
| | | } |
| | | |
| | | public String getServiceImplPathTemplate() { |
| | | return serviceImplPathTemplate; |
| | | } |
| | | |
| | | public void setServiceImplPathTemplate(String serviceImplPathTemplate) { |
| | | this.serviceImplPathTemplate = serviceImplPathTemplate; |
| | | } |
| | | |
| | | public List<String> getServiceImplImports() { |
| | | return serviceImplImports; |
| | | } |
| | | |
| | | public void setServiceImplImports(List<String> serviceImplImports) { |
| | | this.serviceImplImports = serviceImplImports; |
| | | } |
| | | |
| | | public ContextConfig getContextConfig() { |
| | | return contextConfig; |
| | | } |
| | | |
| | | public void setContextConfig(ContextConfig contextConfig) { |
| | | this.contextConfig = contextConfig; |
| | | } |
| | | |
| | | public List<String> getServiceInterfaceImports() { |
| | | return serviceInterfaceImports; |
| | | } |
| | | |
| | | public void setServiceInterfaceImports(List<String> serviceInterfaceImports) { |
| | | this.serviceInterfaceImports = serviceInterfaceImports; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.generator.engine.config; |
| | | |
| | | import com.baomidou.mybatisplus.toolkit.IdWorker; |
| | | import com.stylefeng.guns.core.constant.IsMenu; |
| | | import com.stylefeng.guns.core.util.ToolUtil; |
| | | |
| | | import java.sql.Connection; |
| | | import java.sql.PreparedStatement; |
| | | import java.sql.ResultSet; |
| | | import java.sql.SQLException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 全局配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-08 20:21 |
| | | */ |
| | | public class SqlConfig { |
| | | |
| | | private String sqlPathTemplate; |
| | | |
| | | private ContextConfig contextConfig; |
| | | |
| | | private Connection connection; |
| | | |
| | | private String parentMenuName; |
| | | |
| | | private List<Menu> menus = new ArrayList<>(6); |
| | | |
| | | public void init() { |
| | | |
| | | this.sqlPathTemplate = "\\src\\main\\java\\{}.sql"; |
| | | |
| | | if (parentMenuName == null) { |
| | | return; |
| | | } |
| | | |
| | | //根据父菜单查询数据库中的pcode和pcodes |
| | | String[] pcodeAndPcodes = getPcodeAndPcodes(); |
| | | if (pcodeAndPcodes == null) { |
| | | System.err.println("父级菜单名称输入有误!!!!"); |
| | | return; |
| | | } |
| | | |
| | | //业务菜单 |
| | | Menu menu = new Menu(); |
| | | menu.setId(IdWorker.getId()); |
| | | menu.setCode(contextConfig.getBizEnName()); |
| | | menu.setPcode(pcodeAndPcodes[0]); |
| | | menu.setPcodes(pcodeAndPcodes[1] + "[" + pcodeAndPcodes[0] + "],"); |
| | | menu.setName(contextConfig.getBizChName()); |
| | | menu.setIcon(""); |
| | | menu.setUrl("/" + contextConfig.getBizEnName()); |
| | | menu.setNum(99); |
| | | |
| | | if (parentMenuName.equals("顶级")) { |
| | | menu.setLevels(1); |
| | | } else { |
| | | menu.setLevels(2); |
| | | } |
| | | menu.setIsmenu(IsMenu.YES.getCode()); |
| | | menu.setStatus(1); |
| | | menu.setIsopen(0); |
| | | menus.add(menu); |
| | | |
| | | //列表 |
| | | Menu list = createSubMenu(menu); |
| | | list.setCode(contextConfig.getBizEnName() + "_list"); |
| | | list.setName(contextConfig.getBizChName() + "列表"); |
| | | list.setUrl("/" + contextConfig.getBizEnName() + "/list"); |
| | | menus.add(list); |
| | | |
| | | //添加 |
| | | Menu add = createSubMenu(menu); |
| | | add.setCode(contextConfig.getBizEnName() + "_add"); |
| | | add.setName(contextConfig.getBizChName() + "添加"); |
| | | add.setUrl("/" + contextConfig.getBizEnName() + "/add"); |
| | | menus.add(add); |
| | | |
| | | //更新 |
| | | Menu update = createSubMenu(menu); |
| | | update.setCode(contextConfig.getBizEnName() + "_update"); |
| | | update.setName(contextConfig.getBizChName() + "更新"); |
| | | update.setUrl("/" + contextConfig.getBizEnName() + "/update"); |
| | | menus.add(update); |
| | | |
| | | //删除 |
| | | Menu delete = createSubMenu(menu); |
| | | delete.setCode(contextConfig.getBizEnName() + "_delete"); |
| | | delete.setName(contextConfig.getBizChName() + "删除"); |
| | | delete.setUrl("/" + contextConfig.getBizEnName() + "/delete"); |
| | | menus.add(delete); |
| | | |
| | | //详情 |
| | | Menu detail = createSubMenu(menu); |
| | | detail.setCode(contextConfig.getBizEnName() + "_detail"); |
| | | detail.setName(contextConfig.getBizChName() + "详情"); |
| | | detail.setUrl("/" + contextConfig.getBizEnName() + "/detail"); |
| | | menus.add(detail); |
| | | } |
| | | |
| | | private Menu createSubMenu(Menu parentMenu) { |
| | | Menu menu = new Menu(); |
| | | menu.setId(IdWorker.getId()); |
| | | menu.setPcode(parentMenu.getCode()); |
| | | menu.setPcodes(parentMenu.getPcodes() + "[" + parentMenu.getCode() + "],"); |
| | | menu.setIcon(""); |
| | | menu.setNum(99); |
| | | menu.setLevels(parentMenu.getLevels() + 1); |
| | | menu.setIsmenu(IsMenu.NO.getCode()); |
| | | menu.setStatus(1); |
| | | menu.setIsopen(0); |
| | | return menu; |
| | | } |
| | | |
| | | public String[] getPcodeAndPcodes() { |
| | | if (parentMenuName.equals("顶级")) { |
| | | return new String[]{"0", ""}; |
| | | } |
| | | PreparedStatement preparedStatement = null; |
| | | try { |
| | | preparedStatement = connection.prepareStatement("select * from sys_menu where name like ?"); |
| | | preparedStatement.setString(1, "%" + parentMenuName + "%"); |
| | | ResultSet results = preparedStatement.executeQuery(); |
| | | while (results.next()) { |
| | | String pcode = results.getString("code"); |
| | | String pcodes = results.getString("pcodes"); |
| | | if (ToolUtil.isNotEmpty(pcode) && ToolUtil.isNotEmpty(pcodes)) { |
| | | String[] strings = {pcode, pcodes}; |
| | | return strings; |
| | | } else { |
| | | return null; |
| | | } |
| | | } |
| | | } catch (SQLException e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | // 释放资源 |
| | | try { |
| | | if (preparedStatement != null) { |
| | | preparedStatement.close(); |
| | | } |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | } catch (SQLException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public ContextConfig getContextConfig() { |
| | | return contextConfig; |
| | | } |
| | | |
| | | public void setContextConfig(ContextConfig contextConfig) { |
| | | this.contextConfig = contextConfig; |
| | | } |
| | | |
| | | public String getParentMenuName() { |
| | | return parentMenuName; |
| | | } |
| | | |
| | | public void setParentMenuName(String parentMenuName) { |
| | | this.parentMenuName = parentMenuName; |
| | | } |
| | | |
| | | public Connection getConnection() { |
| | | return connection; |
| | | } |
| | | |
| | | public void setConnection(Connection connection) { |
| | | this.connection = connection; |
| | | } |
| | | |
| | | public String getSqlPathTemplate() { |
| | | return sqlPathTemplate; |
| | | } |
| | | |
| | | public void setSqlPathTemplate(String sqlPathTemplate) { |
| | | this.sqlPathTemplate = sqlPathTemplate; |
| | | } |
| | | |
| | | public List<Menu> getMenus() { |
| | | return menus; |
| | | } |
| | | |
| | | public void setMenus(List<Menu> menus) { |
| | | this.menus = menus; |
| | | } |
| | | } |
New file |
| | |
| | | package ${controller.packageName}; |
| | | |
| | | <% for(import in controller.imports!){ %> |
| | | import ${import}; |
| | | <% } %> |
| | | |
| | | /** |
| | | * ${context.bizChName}控制器 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date ${tool.currentTime()} |
| | | */ |
| | | @Controller |
| | | @RequestMapping("/${context.bizEnName}") |
| | | public class ${context.bizEnBigName}Controller extends BaseController { |
| | | |
| | | private String PREFIX = "/${context.moduleName}/${context.bizEnName}/"; |
| | | |
| | | @Autowired |
| | | private I${context.entityName}Service ${context.bizEnName}Service; |
| | | |
| | | /** |
| | | * 跳转到${context.bizChName}首页 |
| | | */ |
| | | @RequestMapping("") |
| | | public String index() { |
| | | return PREFIX + "${context.bizEnName}.html"; |
| | | } |
| | | |
| | | /** |
| | | * 跳转到添加${context.bizChName} |
| | | */ |
| | | @RequestMapping("/${context.bizEnName}_add") |
| | | public String ${context.bizEnName}Add() { |
| | | return PREFIX + "${context.bizEnName}_add.html"; |
| | | } |
| | | |
| | | /** |
| | | * 跳转到修改${context.bizChName} |
| | | */ |
| | | @RequestMapping("/${context.bizEnName}_update/{${context.bizEnName}Id}") |
| | | public String ${context.bizEnName}Update(@PathVariable Integer ${context.bizEnName}Id, Model model) { |
| | | ${context.entityName} ${context.bizEnName} = ${context.bizEnName}Service.selectById(${context.bizEnName}Id); |
| | | model.addAttribute("item",${context.bizEnName}); |
| | | LogObjectHolder.me().set(${context.bizEnName}); |
| | | return PREFIX + "${context.bizEnName}_edit.html"; |
| | | } |
| | | |
| | | /** |
| | | * 获取${context.bizChName}列表 |
| | | */ |
| | | @RequestMapping(value = "/list") |
| | | @ResponseBody |
| | | public Object list(String condition) { |
| | | return ${context.bizEnName}Service.selectList(null); |
| | | } |
| | | |
| | | /** |
| | | * 新增${context.bizChName} |
| | | */ |
| | | @RequestMapping(value = "/add") |
| | | @ResponseBody |
| | | public Object add(${context.entityName} ${context.bizEnName}) { |
| | | ${context.bizEnName}Service.insert(${context.bizEnName}); |
| | | return SUCCESS_TIP; |
| | | } |
| | | |
| | | /** |
| | | * 删除${context.bizChName} |
| | | */ |
| | | @RequestMapping(value = "/delete") |
| | | @ResponseBody |
| | | public Object delete(@RequestParam Integer ${context.bizEnName}Id) { |
| | | ${context.bizEnName}Service.deleteById(${context.bizEnName}Id); |
| | | return SUCCESS_TIP; |
| | | } |
| | | |
| | | /** |
| | | * 修改${context.bizChName} |
| | | */ |
| | | @RequestMapping(value = "/update") |
| | | @ResponseBody |
| | | public Object update(${context.entityName} ${context.bizEnName}) { |
| | | ${context.bizEnName}Service.updateById(${context.bizEnName}); |
| | | return SUCCESS_TIP; |
| | | } |
| | | |
| | | /** |
| | | * ${context.bizChName}详情 |
| | | */ |
| | | @RequestMapping(value = "/detail/{${context.bizEnName}Id}") |
| | | @ResponseBody |
| | | public Object detail(@PathVariable("${context.bizEnName}Id") Integer ${context.bizEnName}Id) { |
| | | return ${context.bizEnName}Service.selectById(${context.bizEnName}Id); |
| | | } |
| | | } |
New file |
| | |
| | | <% for(menu in sqls.menus!){ %> |
| | | INSERT INTO `guns`.`sys_menu` (`id`, `code`, `pcode`, `pcodes`, `name`, `icon`, `url`, `num`, `levels`, `ismenu`, `tips`, `status`, `isopen`) VALUES ('${menu.id}', '${menu.code}', '${menu.pcode}', '${menu.pcodes}', '${menu.name}', '${menu.icon}', '${menu.url}', '${menu.num}', '${menu.levels}', '${menu.ismenu}', NULL, '${menu.status}', '${menu.isopen}'); |
| | | <% } %> |
New file |
| | |
| | | @layout("/common/_container.html"){ |
| | | <div class="row"> |
| | | <div class="col-sm-12"> |
| | | <div class="ibox float-e-margins"> |
| | | <div class="ibox-title"> |
| | | <h5>${context.bizChName}管理</h5> |
| | | </div> |
| | | <div class="ibox-content"> |
| | | <div class="row row-lg"> |
| | | <div class="col-sm-12"> |
| | | <div class="row"> |
| | | <div class="col-sm-3"> |
| | | <#NameCon id="condition" name="名称" /> |
| | | </div> |
| | | <div class="col-sm-3"> |
| | | <#button name="搜索" icon="fa-search" clickFun="${context.bizEnBigName}.search()"/> |
| | | </div> |
| | | </div> |
| | | <div class="hidden-xs" id="${context.bizEnBigName}TableToolbar" role="group"> |
| | | @if(shiro.hasPermission("/${context.bizEnName}/add")){ |
| | | <#button name="添加" icon="fa-plus" clickFun="${context.bizEnBigName}.openAdd${context.bizEnBigName}()"/> |
| | | @} |
| | | @if(shiro.hasPermission("/${context.bizEnName}/update")){ |
| | | <#button name="修改" icon="fa-edit" clickFun="${context.bizEnBigName}.open${context.bizEnBigName}Detail()" space="true"/> |
| | | @} |
| | | @if(shiro.hasPermission("/${context.bizEnName}/delete")){ |
| | | <#button name="删除" icon="fa-remove" clickFun="${context.bizEnBigName}.delete()" space="true"/> |
| | | @} |
| | | </div> |
| | | <#table id="${context.bizEnBigName}Table"/> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <script src="\${ctxPath}/static/modular/${context.moduleName}/${context.bizEnName}/${context.bizEnName}.js"></script> |
| | | @} |
New file |
| | |
| | | /** |
| | | * ${context.bizChName}管理初始化 |
| | | */ |
| | | var ${context.bizEnBigName} = { |
| | | id: "${context.bizEnBigName}Table", //表格id |
| | | seItem: null, //选中的条目 |
| | | table: null, |
| | | layerIndex: -1 |
| | | }; |
| | | |
| | | /** |
| | | * 初始化表格的列 |
| | | */ |
| | | ${context.bizEnBigName}.initColumn = function () { |
| | | return [ |
| | | {field: 'selectItem', radio: true}, |
| | | <% for(item in table.fields!){ %> |
| | | <% if(itemLP.last != true){ %> |
| | | {title: '${item.comment}', field: '${item.propertyName}', visible: true, align: 'center', valign: 'middle'}, |
| | | <% }else{ %> |
| | | {title: '${item.comment}', field: '${item.propertyName}', visible: true, align: 'center', valign: 'middle'} |
| | | <% }} %> |
| | | ]; |
| | | }; |
| | | |
| | | /** |
| | | * 检查是否选中 |
| | | */ |
| | | ${context.bizEnBigName}.check = function () { |
| | | var selected = $('#' + this.id).bootstrapTable('getSelections'); |
| | | if(selected.length == 0){ |
| | | Feng.info("请先选中表格中的某一记录!"); |
| | | return false; |
| | | }else{ |
| | | ${context.bizEnBigName}.seItem = selected[0]; |
| | | return true; |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 点击添加${context.bizChName} |
| | | */ |
| | | ${context.bizEnBigName}.openAdd${context.bizEnBigName} = function () { |
| | | var index = layer.open({ |
| | | type: 2, |
| | | title: '添加${context.bizChName}', |
| | | area: ['800px', '420px'], //宽高 |
| | | fix: false, //不固定 |
| | | maxmin: true, |
| | | content: Feng.ctxPath + '/${context.bizEnName}/${context.bizEnName}_add' |
| | | }); |
| | | this.layerIndex = index; |
| | | }; |
| | | |
| | | /** |
| | | * 打开查看${context.bizChName}详情 |
| | | */ |
| | | ${context.bizEnBigName}.open${context.bizEnBigName}Detail = function () { |
| | | if (this.check()) { |
| | | var index = layer.open({ |
| | | type: 2, |
| | | title: '${context.bizChName}详情', |
| | | area: ['800px', '420px'], //宽高 |
| | | fix: false, //不固定 |
| | | maxmin: true, |
| | | content: Feng.ctxPath + '/${context.bizEnName}/${context.bizEnName}_update/' + ${context.bizEnBigName}.seItem.id |
| | | }); |
| | | this.layerIndex = index; |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 删除${context.bizChName} |
| | | */ |
| | | ${context.bizEnBigName}.delete = function () { |
| | | if (this.check()) { |
| | | var ajax = new $ax(Feng.ctxPath + "/${context.bizEnName}/delete", function (data) { |
| | | Feng.success("删除成功!"); |
| | | ${context.bizEnBigName}.table.refresh(); |
| | | }, function (data) { |
| | | Feng.error("删除失败!" + data.responseJSON.message + "!"); |
| | | }); |
| | | ajax.set("${context.bizEnName}Id",this.seItem.id); |
| | | ajax.start(); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 查询${context.bizChName}列表 |
| | | */ |
| | | ${context.bizEnBigName}.search = function () { |
| | | var queryData = {}; |
| | | queryData['condition'] = $("#condition").val(); |
| | | ${context.bizEnBigName}.table.refresh({query: queryData}); |
| | | }; |
| | | |
| | | $(function () { |
| | | var defaultColunms = ${context.bizEnBigName}.initColumn(); |
| | | var table = new BSTable(${context.bizEnBigName}.id, "/${context.bizEnName}/list", defaultColunms); |
| | | table.setPaginationType("client"); |
| | | ${context.bizEnBigName}.table = table.init(); |
| | | }); |
New file |
| | |
| | | @layout("/common/_container.html"){ |
| | | <div class="ibox float-e-margins"> |
| | | <div class="ibox-content"> |
| | | <div class="form-horizontal"> |
| | | |
| | | <div class="row"> |
| | | <div class="col-sm-6 b-r"> |
| | | <% var leftSize = tool.toInt((table.fields.~size + 1) / 2); %> |
| | | <% var rightSize = tool.toInt(table.fields.~size - leftSize); %> |
| | | <% for(var i=0;i<leftSize;i++){ %> |
| | | <% if(i != (leftSize-1) ){ %> |
| | | <#input id="${table.fields[i].propertyName}" name="${table.fields[i].comment}" underline="true"/> |
| | | <% }else{ %> |
| | | <#input id="${table.fields[i].propertyName}" name="${table.fields[i].comment}"/> |
| | | <% } %> |
| | | <% } %> |
| | | </div> |
| | | |
| | | <div class="col-sm-6"> |
| | | <% for(var i=leftSize;i<table.fields.~size;i++){ %> |
| | | <% if(i != (rightSize-1) ){ %> |
| | | <#input id="${table.fields[i].propertyName}" name="${table.fields[i].comment}" underline="true"/> |
| | | <% }else{ %> |
| | | <#input id="${table.fields[i].propertyName}" name="${table.fields[i].comment}"/> |
| | | <% } %> |
| | | <% } %> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="row btn-group-m-t"> |
| | | <div class="col-sm-10"> |
| | | <#button btnCss="info" name="提交" id="ensure" icon="fa-check" clickFun="${context.bizEnBigName}InfoDlg.addSubmit()"/> |
| | | <#button btnCss="danger" name="取消" id="cancel" icon="fa-eraser" clickFun="${context.bizEnBigName}InfoDlg.close()"/> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | <script src="\${ctxPath}/static/modular/${context.moduleName}/${context.bizEnName}/${context.bizEnName}_info.js"></script> |
| | | @} |
New file |
| | |
| | | @layout("/common/_container.html"){ |
| | | <div class="ibox float-e-margins"> |
| | | <div class="ibox-content"> |
| | | <div class="form-horizontal"> |
| | | |
| | | <div class="row"> |
| | | <div class="col-sm-6 b-r"> |
| | | <% var leftSize = tool.toInt((table.fields.~size + 1) / 2); %> |
| | | <% var rightSize = tool.toInt(table.fields.~size - leftSize); %> |
| | | <% for(var i=0;i<leftSize;i++){ %> |
| | | <% if(i != (leftSize-1) ){ %> |
| | | <#input id="${table.fields[i].propertyName}" name="${table.fields[i].comment}" value="\${item.${table.fields[i].propertyName}}" underline="true"/> |
| | | <% }else{ %> |
| | | <#input id="${table.fields[i].propertyName}" name="${table.fields[i].comment}" value="\${item.${table.fields[i].propertyName}}" /> |
| | | <% } %> |
| | | <% } %> |
| | | </div> |
| | | |
| | | <div class="col-sm-6"> |
| | | <% for(var i=leftSize;i<table.fields.~size;i++){ %> |
| | | <% if(i != (table.fields.~size-1) ){ %> |
| | | <#input id="${table.fields[i].propertyName}" name="${table.fields[i].comment}" value="\${item.${table.fields[i].propertyName}}" underline="true"/> |
| | | <% }else{ %> |
| | | <#input id="${table.fields[i].propertyName}" name="${table.fields[i].comment}" value="\${item.${table.fields[i].propertyName}}" /> |
| | | <% } %> |
| | | <% } %> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="row btn-group-m-t"> |
| | | <div class="col-sm-10"> |
| | | <#button btnCss="info" name="提交" id="ensure" icon="fa-check" clickFun="${context.bizEnBigName}InfoDlg.editSubmit()"/> |
| | | <#button btnCss="danger" name="取消" id="cancel" icon="fa-eraser" clickFun="${context.bizEnBigName}InfoDlg.close()"/> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | <script src="\${ctxPath}/static/modular/${context.moduleName}/${context.bizEnName}/${context.bizEnName}_info.js"></script> |
| | | @} |
New file |
| | |
| | | /** |
| | | * 初始化${context.bizChName}详情对话框 |
| | | */ |
| | | var ${context.bizEnBigName}InfoDlg = { |
| | | ${context.bizEnName}InfoData : {} |
| | | }; |
| | | |
| | | /** |
| | | * 清除数据 |
| | | */ |
| | | ${context.bizEnBigName}InfoDlg.clearData = function() { |
| | | this.${context.bizEnName}InfoData = {}; |
| | | } |
| | | |
| | | /** |
| | | * 设置对话框中的数据 |
| | | * |
| | | * @param key 数据的名称 |
| | | * @param val 数据的具体值 |
| | | */ |
| | | ${context.bizEnBigName}InfoDlg.set = function(key, val) { |
| | | this.${context.bizEnName}InfoData[key] = (typeof val == "undefined") ? $("#" + key).val() : val; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置对话框中的数据 |
| | | * |
| | | * @param key 数据的名称 |
| | | * @param val 数据的具体值 |
| | | */ |
| | | ${context.bizEnBigName}InfoDlg.get = function(key) { |
| | | return $("#" + key).val(); |
| | | } |
| | | |
| | | /** |
| | | * 关闭此对话框 |
| | | */ |
| | | ${context.bizEnBigName}InfoDlg.close = function() { |
| | | parent.layer.close(window.parent.${context.bizEnBigName}.layerIndex); |
| | | } |
| | | |
| | | /** |
| | | * 收集数据 |
| | | */ |
| | | ${context.bizEnBigName}InfoDlg.collectData = function() { |
| | | this |
| | | <% for(item in table.fields!){ %> |
| | | <% if(itemLP.last != true){ %> |
| | | .set('${item.propertyName}') |
| | | <% }else{ %> |
| | | .set('${item.propertyName}'); |
| | | <% }} %> |
| | | } |
| | | |
| | | /** |
| | | * 提交添加 |
| | | */ |
| | | ${context.bizEnBigName}InfoDlg.addSubmit = function() { |
| | | |
| | | this.clearData(); |
| | | this.collectData(); |
| | | |
| | | //提交信息 |
| | | var ajax = new $ax(Feng.ctxPath + "/${context.bizEnName}/add", function(data){ |
| | | Feng.success("添加成功!"); |
| | | window.parent.${context.bizEnBigName}.table.refresh(); |
| | | ${context.bizEnBigName}InfoDlg.close(); |
| | | },function(data){ |
| | | Feng.error("添加失败!" + data.responseJSON.message + "!"); |
| | | }); |
| | | ajax.set(this.${context.bizEnName}InfoData); |
| | | ajax.start(); |
| | | } |
| | | |
| | | /** |
| | | * 提交修改 |
| | | */ |
| | | ${context.bizEnBigName}InfoDlg.editSubmit = function() { |
| | | |
| | | this.clearData(); |
| | | this.collectData(); |
| | | |
| | | //提交信息 |
| | | var ajax = new $ax(Feng.ctxPath + "/${context.bizEnName}/update", function(data){ |
| | | Feng.success("修改成功!"); |
| | | window.parent.${context.bizEnBigName}.table.refresh(); |
| | | ${context.bizEnBigName}InfoDlg.close(); |
| | | },function(data){ |
| | | Feng.error("修改失败!" + data.responseJSON.message + "!"); |
| | | }); |
| | | ajax.set(this.${context.bizEnName}InfoData); |
| | | ajax.start(); |
| | | } |
| | | |
| | | $(function() { |
| | | |
| | | }); |
New file |
| | |
| | | <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.stylefeng</groupId> |
| | | <artifactId>guns-parent</artifactId> |
| | | <version>1.0.0</version> |
| | | |
| | | <name>guns-parent</name> |
| | | <packaging>pom</packaging> |
| | | |
| | | <modules> |
| | | <module>guns-admin</module> |
| | | <module>guns-core</module> |
| | | <module>guns-rest</module> |
| | | <module>guns-generator</module> |
| | | </modules> |
| | | |
| | | <parent> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-parent</artifactId> |
| | | <version>2.0.4.RELEASE</version> |
| | | </parent> |
| | | |
| | | <properties> |
| | | <spring-cloud.version>Finchley.SR1</spring-cloud.version> |
| | | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
| | | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
| | | <java.version>1.8</java.version> |
| | | <guns.version>1.0.0</guns.version> |
| | | <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version> |
| | | <shiro.version>1.4.0</shiro.version> |
| | | <mybatis-plus.version>2.3</mybatis-plus.version> |
| | | <fastjson.version>1.2.47</fastjson.version> |
| | | <velocity.version>1.7</velocity.version> |
| | | <kaptcha.version>2.3.2</kaptcha.version> |
| | | <ehcache.version>3.3.1</ehcache.version> |
| | | <zxing.version>3.2.1</zxing.version> |
| | | <druid.version>1.1.10</druid.version> |
| | | <beetl.version>2.8.5</beetl.version> |
| | | <swagger.version>2.9.2</swagger.version> |
| | | <commons-lang3.version>3.7</commons-lang3.version> |
| | | <ehcache.core.version>2.6.11</ehcache.core.version> |
| | | <mysql-connector-java.version>8.0.11</mysql-connector-java.version> |
| | | <jwt.version>0.9.0</jwt.version> |
| | | <hutool.version>4.1.1</hutool.version> |
| | | </properties> |
| | | |
| | | <dependencyManagement> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>org.springframework.cloud</groupId> |
| | | <artifactId>spring-cloud-dependencies</artifactId> |
| | | <version>${spring-cloud.version}</version> |
| | | <type>pom</type> |
| | | <scope>import</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.stylefeng</groupId> |
| | | <artifactId>guns-generator</artifactId> |
| | | <version>${guns.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.stylefeng</groupId> |
| | | <artifactId>guns-core</artifactId> |
| | | <version>${guns.version}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-dependencies</artifactId> |
| | | <version>2.0.1.RELEASE</version> |
| | | <type>pom</type> |
| | | <scope>import</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.baomidou</groupId> |
| | | <artifactId>mybatisplus-spring-boot-starter</artifactId> |
| | | <version>${mybatisplus-spring-boot-starter.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-spring</artifactId> |
| | | <version>${shiro.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shiro</groupId> |
| | | <artifactId>shiro-ehcache</artifactId> |
| | | <version>${shiro.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>mysql</groupId> |
| | | <artifactId>mysql-connector-java</artifactId> |
| | | <version>${mysql-connector-java.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.baomidou</groupId> |
| | | <artifactId>mybatis-plus</artifactId> |
| | | <version>${mybatis-plus.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.baomidou</groupId> |
| | | <artifactId>mybatis-plus-generate</artifactId> |
| | | <version>${mybatis-plus.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>fastjson</artifactId> |
| | | <version>${fastjson.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>druid</artifactId> |
| | | <version>${druid.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.github.penggle</groupId> |
| | | <artifactId>kaptcha</artifactId> |
| | | <version>${kaptcha.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.ehcache</groupId> |
| | | <artifactId>ehcache</artifactId> |
| | | <version>${ehcache.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.google.zxing</groupId> |
| | | <artifactId>core</artifactId> |
| | | <version>${zxing.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.velocity</groupId> |
| | | <artifactId>velocity</artifactId> |
| | | <version>${velocity.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.ibeetl</groupId> |
| | | <artifactId>beetl</artifactId> |
| | | <version>${beetl.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.springfox</groupId> |
| | | <artifactId>springfox-swagger2</artifactId> |
| | | <version>${swagger.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.springfox</groupId> |
| | | <artifactId>springfox-swagger-ui</artifactId> |
| | | <version>${swagger.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.commons</groupId> |
| | | <artifactId>commons-lang3</artifactId> |
| | | <version>${commons-lang3.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>net.sf.ehcache</groupId> |
| | | <artifactId>ehcache-core</artifactId> |
| | | <version>${ehcache.core.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.jsonwebtoken</groupId> |
| | | <artifactId>jjwt</artifactId> |
| | | <version>${jwt.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>cn.hutool</groupId> |
| | | <artifactId>hutool-all</artifactId> |
| | | <version>${hutool.version}</version> |
| | | </dependency> |
| | | </dependencies> |
| | | </dependencyManagement> |
| | | |
| | | <build> |
| | | <pluginManagement> |
| | | <plugins> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-compiler-plugin</artifactId> |
| | | <version>3.1</version> |
| | | <configuration> |
| | | <source>${java.version}</source> |
| | | <target>${java.version}</target> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-maven-plugin</artifactId> |
| | | </plugin> |
| | | </plugins> |
| | | </pluginManagement> |
| | | <plugins> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-resources-plugin</artifactId> |
| | | <configuration> |
| | | <delimiters> |
| | | <delimiter>@</delimiter> |
| | | </delimiters> |
| | | <useDefaultDelimiters>false</useDefaultDelimiters> |
| | | </configuration> |
| | | </plugin> |
| | | </plugins> |
| | | <resources> |
| | | <resource> |
| | | <directory>src/main/resources</directory> |
| | | <filtering>true</filtering> |
| | | </resource> |
| | | <resource> |
| | | <directory>src/main/java</directory> |
| | | <includes> |
| | | <include>**/*.xml</include> |
| | | </includes> |
| | | </resource> |
| | | </resources> |
| | | </build> |
| | | |
| | | <profiles> |
| | | <profile> |
| | | <id>local</id> |
| | | <properties> |
| | | <spring.active>local</spring.active> |
| | | </properties> |
| | | <activation> |
| | | <activeByDefault>true</activeByDefault> |
| | | </activation> |
| | | </profile> |
| | | <profile> |
| | | <id>dev</id> |
| | | <properties> |
| | | <spring.active>dev</spring.active> |
| | | </properties> |
| | | </profile> |
| | | <profile> |
| | | <id>test</id> |
| | | <properties> |
| | | <spring.active>test</spring.active> |
| | | </properties> |
| | | </profile> |
| | | <profile> |
| | | <id>produce</id> |
| | | <properties> |
| | | <spring.active>produce</spring.active> |
| | | </properties> |
| | | </profile> |
| | | </profiles> |
| | | |
| | | </project> |
New file |
| | |
| | | *.js linguist-language=java |
| | | *.css linguist-language=java |
| | | *.html linguist-language=java |
| | | *.btl linguist-language=java |
New file |
| | |
| | | # Compiled class file |
| | | *.class |
| | | *.iml |
| | | *.idea |
| | | target/ |
| | | logs/ |
| | | |
| | | # Log file |
| | | *.log |
| | | |
| | | # BlueJ files |
| | | *.ctxt |
| | | |
| | | # Mobile Tools for Java (J2ME) |
| | | .mtj.tmp/ |
| | | |
| | | # Package Files # |
| | | *.jar |
| | | *.war |
| | | *.ear |
| | | *.zip |
| | | *.tar.gz |
| | | *.rar |
| | | |
| | | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml |
| | | hs_err_pid* |
| | | |
| | | *velocity.log* |
| | | |
| | | # Eclipse # |
| | | .classpath |
| | | .project |
| | | .settings/ |
New file |
| | |
| | | Copyright 2018 StyleFeng |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
New file |
| | |
| | | # Guns V4.1 |
| | | |
| | | ## 介绍 |
| | | Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + mybatis-plus + beetl!Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作为一个后台管理系统的脚手架! 2018目标 `更简洁`,`更规范`! |
| | | |
| | | Guns v3.0新增rest api服务,提供对接服务端接口的支持,并利用jwt token鉴权机制给予客户端的访问权限,传输数据进行md5签名保证传输过程数据的安全性! |
| | | |
| | | ### Guns v4.1更新内容 |
| | | |
| | | > * guns-admin提供rest api服务,并以jwt方式鉴权,所有以`/gunsApi`开头的接口走这种鉴权方式,其他接口仍为shiro鉴权 |
| | | |
| | | ### Guns v4.0更新内容 |
| | | |
| | | > * spring boot升级到2.0版本! |
| | | > * 简化前端所有的html,js,css等资源文件,由11.8MB缩减为4.8MB! |
| | | > * 新增手动增加标签页的方法,Feng.newCrontab(href,menuName); |
| | | > * laydate时间插件和layer弹出层插件更新为官网最新,可以看着layui官网的文档直接开发啦! |
| | | > * 去掉animate动画效果,加快页面响应速度! |
| | | > * 修复登陆后重启应用造成404的bug! |
| | | > * 增强core模块的功能,拿来即用开发新的模块的后端管理系统! |
| | | > * 升级各个依赖包的版本! |
| | | > * 简化applicatioin.yml的配置,一些固定不变的配置写在core模块的default-config.properties! |
| | | > * 简化多数据源配置,简化mybatis-plus的配置! |
| | | > * 优化日志记录格式和策略,详情见logback-spring.xml! |
| | | |
| | | 此外,**更新Guns文档到《Guns技术文档 v2.0》** |
| | | |
| | | ## 最新Guns技术文档 |
| | | Guns框架有作者在业余时间整理的技术文档,详情点击[查看详情](https://gitee.com/naan1993/guns/wikis/pages?title=Guns%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3&parent=) |
| | | |
| | | ## 最新Guns视频教程 |
| | | Guns框架有作者在业余时间录制的视频教程,详情点击[教程介绍](https://gitee.com/naan1993/guns/wikis/pages?title=Guns%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B&parent=) |
| | | |
| | | ## 技术讨论 & [wiki地址](https://gitee.com/naan1993/guns/wikis/Home) |
| | | 如果对项目有任何疑问或者建议,欢迎加入Guns技术交流1群:254550081,Guns技术交流2群:684163663,Guns技术交流3群:207434260(加之前先看下文档guns-admin/doc/Guns技术文档 v1.0.pdf) |
| | | |
| | | ## 管理系统功能 |
| | | 1.用户管理 2.角色管理 3.部门管理 4.菜单管理 5.字典管理 6.业务日志 7.登录日志 8.监控管理 9.通知管理 10.代码生成 |
| | | |
| | | ## 项目特点 |
| | | 1. 基于SpringBoot,简化了大量项目配置和maven依赖,让您更专注于业务开发,独特的分包方式,代码多而不乱。 |
| | | 2. 完善的日志记录体系,可记录登录日志,业务操作日志(可记录操作前和操作后的数据),异常日志到数据库,通过@BussinessLog注解和LogObjectHolder.me().set()方法,业务操作日志可具体记录哪个用户,执行了哪些业务,修改了哪些数据,并且日志记录为异步执行,详情请见@BussinessLog注解和LogObjectHolder,LogManager,LogAop类。 |
| | | 3. 利用beetl模板引擎对前台页面进行封装和拆分,使臃肿的html代码变得简洁,更加易维护。 |
| | | 4. 对常用js插件进行二次封装,使js代码变得简洁,更加易维护,具体请见webapp/static/js/common文件夹内js代码。 |
| | | 5. 利用ehcache框架对经常调用的查询进行缓存,提升运行速度,具体请见ConstantFactory类中@Cacheable标记的方法。 |
| | | 6. controller层采用map + warpper方式的返回结果,返回给前端更为灵活的数据,具体参见com.stylefeng.guns.modular.system.warpper包中具体类。 |
| | | 7. 防止XSS攻击,通过XssFilter类对所有的输入的非法字符串进行过滤以及替换。 |
| | | 8. 简单可用的代码生成体系,通过SimpleTemplateEngine可生成带有主页跳转和增删改查的通用控制器、html页面以及相关的js,还可以生成Service和Dao,并且这些生成项都为可选的,通过ContextConfig下的一些列xxxSwitch开关,可灵活控制生成模板代码,让您把时间放在真正的业务上。 |
| | | 9. 控制器层统一的异常拦截机制,利用@ControllerAdvice统一对异常拦截,具体见com.stylefeng.guns.core.aop.GlobalExceptionHandler类。 |
| | | 10. 页面统一的js key-value单例模式写法,每个页面生成一个唯一的全局变量,提高js的利用效率,并且有效防止多个人员开发引起的函数名/类名冲突,并且可以更好地去维护代码。 |
| | | |
| | | ## 基于javabean方式的spring配置 |
| | | Guns以简洁为核心,抛弃了传统的易错,臃肿xml配置,采用javabean的方式配置spring,简化了项目的配置,如下示例为配置mybatis-plus和数据源: |
| | | ``` |
| | | @Configuration |
| | | @MapperScan(basePackages = {"com.stylefeng.guns.modular.*.dao", "com.stylefeng.guns.common.persistence.dao"}) |
| | | public class MybatisPlusConfig { |
| | | |
| | | @Autowired |
| | | DruidProperties druidProperties; |
| | | |
| | | /** |
| | | * mybatis-plus分页插件 |
| | | */ |
| | | @Bean |
| | | public PaginationInterceptor paginationInterceptor() { |
| | | PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); |
| | | paginationInterceptor.setDialectType(DBType.MYSQL.getDb()); |
| | | return paginationInterceptor; |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## 业务日志记录 |
| | | 日志记录采用aop(LogAop类)方式对所有包含@BussinessLog注解的方法进行aop切入,会记录下当前用户执行了哪些操作(即@BussinessLog value属性的内容),如果涉及到数据修改,会取当前http请求的所有requestParameters与LogObjectHolder类中缓存的Object对象的所有字段作比较(所以在编辑之前的获取详情接口中需要缓存被修改对象之前的字段信息),日志内容会异步存入数据库中(通过ScheduledThreadPoolExecutor类)。 |
| | | |
| | | ## beetl对前台页面的拆分与包装 |
| | | 例如,把主页拆分成三部分,每个部分单独一个页面,更加便于维护 |
| | | ``` |
| | | <!--左侧导航开始--> |
| | | @include("/common/_tab.html"){} |
| | | <!--左侧导航结束--> |
| | | |
| | | <!--右侧部分开始--> |
| | | @include("/common/_right.html"){} |
| | | <!--右侧部分结束--> |
| | | |
| | | <!--右侧边栏开始--> |
| | | @include("/common/_theme.html"){} |
| | | <!--右侧边栏结束--> |
| | | ``` |
| | | 以及对重复的html进行包装,使前端页面更加专注于业务实现,例如,把所有页面引用包进行提取 |
| | | ``` |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <meta charset="utf-8"> |
| | | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | | <meta name="renderer" content="webkit" /><!-- 让360浏览器默认选择webkit内核 --> |
| | | |
| | | <!-- 全局css --> |
| | | <link rel="shortcut icon" href="${ctxPath}/static/favicon.ico"> |
| | | <!-- 全局js --> |
| | | <script src="${ctxPath}/static/js/jquery.min.js?v=2.1.4"></script> |
| | | <body class="gray-bg"> |
| | | <div class="wrapper wrapper-content"> |
| | | ${layoutContent} |
| | | </div> |
| | | <script src="${ctxPath}/static/js/content.js?v=1.0.0"></script> |
| | | </body> |
| | | </html> |
| | | ``` |
| | | 开发页面时,只需编写如下代码即可 |
| | | ``` |
| | | @layout("/common/_container.html"){ |
| | | <div class="row"> |
| | | <div class="col-sm-12"> |
| | | <div class="ibox float-e-margins"> |
| | | <div class="ibox-title"> |
| | | <h5>部门管理</h5> |
| | | </div> |
| | | <div class="ibox-content"> |
| | | //自定义内容 |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <script src="${ctxPath}/static/modular/system/dept/dept.js"></script> |
| | | @} |
| | | ``` |
| | | 以上beetl的用法请参考beetl说明文档。 |
| | | |
| | | ## 对js常用代码的封装 |
| | | 在webapp/static/js/common目录中,有对常用js代码的封装,例如Feng.js,其中Feng.info(),Feng.success(),Feng.error()三个方法,分别封装了普通提示,成功提示,错误提示的代码,简化了layer提示层插件的使用。 |
| | | |
| | | ## 极简的图片上传方法 |
| | | guns对web-upload进行二次封装,让图片的上传功能呢只用2行代码即可实现,如下 |
| | | ``` |
| | | var avatarUp = new $WebUpload("avatar"); |
| | | avatarUp.init(); |
| | | ``` |
| | | 具体实现请参考static/js/common/web-upload-object.js |
| | | |
| | | ## 独创controller层,map+warpper返回方式 |
| | | map+warpper方式即为把controller层的返回结果使用BeanKit工具类把原有bean转化为Map的的形式(或者原有bean直接是map的形式),再用单独写的一个包装类再包装一次这个map,使里面的参数更加具体,更加有含义,下面举一个例子,例如,在返回给前台一个性别时,数据库查出来1是男2是女,假如直接返回给前台,那么前台显示的时候还需要增加一次判断,并且前后端分离开发时又增加了一次交流和文档的成本,但是采用warpper包装的形式,可以直接把返回结果包装一下,例如动态增加一个字段sexName直接返回给前台性别的中文名称即可。 |
| | | |
| | | ## 独创mybatis数据范围拦截器,实现对数据权限的过滤 |
| | | Guns的数据范围控制是指,对拥有相同角色的用户,根据部门的不同进行相应的数据筛选,如果部门不相同,那么有可能展示出的具体数据是不一致的.所以说Guns对数据范围控制是以部门id为单位来标识的,如何增加数据范围拦截呢?只需在相关的mapper接口的参数中增加一个DataScope对象即可,DataScope中有两个字段,scopeName用来标识sql语句中部门id的字段名称,例如deptiid或者id,另一个字段deptIds就是具体需要过滤的部门id的集合.拦截器原理如下:拦截mapper中包含DataScope对象的方法,获取其原始sql,并做一个包装限制部门id在deptIds范围内的数据进行展示. |
| | | |
| | | ## swagger api管理使用说明 |
| | | swagger会管理所有包含@ApiOperation注解的控制器方法,同时,可利用@ApiImplicitParams注解标记接口中的参数,具体用法请参考CodeController类中的用法。 |
| | | ``` |
| | | @ApiOperation("生成代码") |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "moduleName", value = "模块名称", required = true, dataType = "String"), |
| | | @ApiImplicitParam(name = "bizChName", value = "业务名称", required = true, dataType = "String"), |
| | | @ApiImplicitParam(name = "bizEnName", value = "业务英文名称", required = true, dataType = "String"), |
| | | @ApiImplicitParam(name = "path", value = "项目生成类路径", required = true, dataType = "String") |
| | | }) |
| | | @RequestMapping(value = "/generate", method = RequestMethod.POST) |
| | | ``` |
| | | |
| | | ## jwt token鉴权机制 |
| | | jwt token鉴权机制是指若需要请求服务器接口,必须通过AuthController获取一个请求令牌(jwt token),持有jwt token的用户才可以访问服务器的其他资源,如果没有此令牌,则访问接口会直接忽略,请求获取jwt token时,需要携带credenceName和credenceCode(可以是账号密码,可以是手机号验证码等等),校验credenceName和credenceCode成功后,会颁发给客户端一个jwt token还有一个随机字符串,用于传输过程中对数据进行签名用,签名机制请见下面介绍.基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息.这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利. |
| | | |
| | | ## 签名机制 |
| | | 签名机制是指客户端向服务端传输数据中,对传输数据进行md5加密,并且加密过程中利用Auth接口返回的随机字符串进行混淆加密,并把md5值同时附带给服务端,服务端通获取数据之后对数据再进行一次md5加密,若加密结果和客户端传来的数据一致,则认定客户端请求的数据是没有被篡改的,若不一致,则认为被加密的数据是被篡改的 |
| | | |
| | | ## 效果图 |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | |  |
| | | |
| | | ## 曾获荣誉 |
| | |  |
New file |
| | |
| | | <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"> |
| | | <parent> |
| | | <groupId>com.stylefeng</groupId> |
| | | <artifactId>guns-parent</artifactId> |
| | | <version>1.0.0</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | |
| | | <artifactId>guns-core</artifactId> |
| | | <packaging>jar</packaging> |
| | | |
| | | <name>guns-core</name> |
| | | <url>http://maven.apache.org</url> |
| | | |
| | | <dependencies> |
| | | |
| | | <!--通用依赖--> |
| | | <dependency> |
| | | <groupId>com.baomidou</groupId> |
| | | <artifactId>mybatisplus-spring-boot-starter</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.baomidou</groupId> |
| | | <artifactId>mybatis-plus</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.velocity</groupId> |
| | | <artifactId>velocity</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>mysql</groupId> |
| | | <artifactId>mysql-connector-java</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-jdbc</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>druid</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>fastjson</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.commons</groupId> |
| | | <artifactId>commons-lang3</artifactId> |
| | | </dependency> |
| | | |
| | | <!--web--> |
| | | <dependency> |
| | | <groupId>javax.servlet</groupId> |
| | | <artifactId>javax.servlet-api</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-web</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | |
| | | <!--aop--> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-aop</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | |
| | | <!--二维码--> |
| | | <dependency> |
| | | <groupId>com.google.zxing</groupId> |
| | | <artifactId>core</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | |
| | | <!--缓存--> |
| | | <dependency> |
| | | <groupId>org.ehcache</groupId> |
| | | <artifactId>ehcache</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-cache</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>net.sf.ehcache</groupId> |
| | | <artifactId>ehcache-core</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-configuration-processor</artifactId> |
| | | <optional>true</optional> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | <build> |
| | | <resources> |
| | | <resource> |
| | | <directory>src/main/resources</directory> |
| | | </resource> |
| | | </resources> |
| | | </build> |
| | | </project> |
New file |
| | |
| | | package com.stylefeng.guns.core; |
| | | |
| | | /** |
| | | * 此类用来获取core模块的包路径 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/12/5 下午12:44 |
| | | */ |
| | | public class CoreFlag { |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.aop; |
| | | |
| | | import com.stylefeng.guns.core.base.tips.ErrorTip; |
| | | import com.stylefeng.guns.core.exception.GunsException; |
| | | import com.stylefeng.guns.core.exception.GunsExceptionEnum; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.web.bind.annotation.ExceptionHandler; |
| | | import org.springframework.web.bind.annotation.ResponseBody; |
| | | import org.springframework.web.bind.annotation.ResponseStatus; |
| | | |
| | | /** |
| | | * 全局的的异常拦截器(拦截所有的控制器)(带有@RequestMapping注解的方法上都会拦截) |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月12日 下午3:19:56 |
| | | */ |
| | | public class BaseControllerExceptionHandler { |
| | | |
| | | private Logger log = LoggerFactory.getLogger(this.getClass()); |
| | | |
| | | /** |
| | | * 拦截业务异常 |
| | | */ |
| | | @ExceptionHandler(GunsException.class) |
| | | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) |
| | | @ResponseBody |
| | | public ErrorTip notFount(GunsException e) { |
| | | log.error("业务异常:", e); |
| | | return new ErrorTip(e.getCode(), e.getMessage()); |
| | | } |
| | | |
| | | /** |
| | | * 拦截未知的运行时异常 |
| | | */ |
| | | @ExceptionHandler(RuntimeException.class) |
| | | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) |
| | | @ResponseBody |
| | | public ErrorTip notFount(RuntimeException e) { |
| | | log.error("运行时异常:", e); |
| | | return new ErrorTip(GunsExceptionEnum.SERVER_ERROR.getCode(), GunsExceptionEnum.SERVER_ERROR.getMessage()); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.controller; |
| | | |
| | | import com.baomidou.mybatisplus.plugins.Page; |
| | | import com.stylefeng.guns.core.base.tips.SuccessTip; |
| | | import com.stylefeng.guns.core.base.warpper.BaseControllerWarpper; |
| | | import com.stylefeng.guns.core.page.PageInfoBT; |
| | | import com.stylefeng.guns.core.support.HttpKit; |
| | | import com.stylefeng.guns.core.util.FileUtil; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.http.ResponseEntity; |
| | | |
| | | import javax.servlet.http.Cookie; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import javax.servlet.http.HttpSession; |
| | | import java.io.UnsupportedEncodingException; |
| | | |
| | | public class BaseController { |
| | | |
| | | protected static String SUCCESS = "SUCCESS"; |
| | | protected static String ERROR = "ERROR"; |
| | | |
| | | protected static String REDIRECT = "redirect:"; |
| | | protected static String FORWARD = "forward:"; |
| | | |
| | | protected static SuccessTip SUCCESS_TIP = new SuccessTip(); |
| | | |
| | | protected HttpServletRequest getHttpServletRequest() { |
| | | return HttpKit.getRequest(); |
| | | } |
| | | |
| | | protected HttpServletResponse getHttpServletResponse() { |
| | | return HttpKit.getResponse(); |
| | | } |
| | | |
| | | protected HttpSession getSession() { |
| | | return HttpKit.getRequest().getSession(); |
| | | } |
| | | |
| | | protected HttpSession getSession(Boolean flag) { |
| | | return HttpKit.getRequest().getSession(flag); |
| | | } |
| | | |
| | | protected String getPara(String name) { |
| | | return HttpKit.getRequest().getParameter(name); |
| | | } |
| | | |
| | | protected void setAttr(String name, Object value) { |
| | | HttpKit.getRequest().setAttribute(name, value); |
| | | } |
| | | |
| | | protected Integer getSystemInvokCount() { |
| | | return (Integer) this.getHttpServletRequest().getServletContext().getAttribute("systemCount"); |
| | | } |
| | | |
| | | /** |
| | | * 把service层的分页信息,封装为bootstrap table通用的分页封装 |
| | | */ |
| | | protected <T> PageInfoBT<T> packForBT(Page<T> page) { |
| | | return new PageInfoBT<T>(page); |
| | | } |
| | | |
| | | /** |
| | | * 包装一个list,让list增加额外属性 |
| | | */ |
| | | protected Object warpObject(BaseControllerWarpper warpper) { |
| | | return warpper.warp(); |
| | | } |
| | | |
| | | /** |
| | | * 删除cookie |
| | | */ |
| | | protected void deleteCookieByName(String cookieName) { |
| | | Cookie[] cookies = this.getHttpServletRequest().getCookies(); |
| | | for (Cookie cookie : cookies) { |
| | | if (cookie.getName().equals(cookieName)) { |
| | | Cookie temp = new Cookie(cookie.getName(), ""); |
| | | temp.setMaxAge(0); |
| | | this.getHttpServletResponse().addCookie(temp); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 删除所有cookie |
| | | */ |
| | | protected void deleteAllCookie() { |
| | | Cookie[] cookies = this.getHttpServletRequest().getCookies(); |
| | | for (Cookie cookie : cookies) { |
| | | Cookie temp = new Cookie(cookie.getName(), ""); |
| | | temp.setMaxAge(0); |
| | | this.getHttpServletResponse().addCookie(temp); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 返回前台文件流 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月28日 下午2:53:19 |
| | | */ |
| | | protected ResponseEntity<byte[]> renderFile(String fileName, String filePath) { |
| | | byte[] bytes = FileUtil.toByteArray(filePath); |
| | | return renderFile(fileName, bytes); |
| | | } |
| | | |
| | | /** |
| | | * 返回前台文件流 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月28日 下午2:53:19 |
| | | */ |
| | | protected ResponseEntity<byte[]> renderFile(String fileName, byte[] fileBytes) { |
| | | String dfileName = null; |
| | | try { |
| | | dfileName = new String(fileName.getBytes("gb2312"), "iso8859-1"); |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); |
| | | headers.setContentDispositionFormData("attachment", dfileName); |
| | | return new ResponseEntity<byte[]>(fileBytes, headers, HttpStatus.CREATED); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.controller; |
| | | |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.ui.Model; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | |
| | | /** |
| | | * 全局的控制器 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月13日 下午11:04:45 |
| | | */ |
| | | @Controller |
| | | @RequestMapping("/global") |
| | | public class GlobalController { |
| | | |
| | | /** |
| | | * 跳转到404页面 |
| | | * |
| | | * @author fengshuonan |
| | | */ |
| | | @RequestMapping(path = "/error") |
| | | public String errorPage() { |
| | | return "/404.html"; |
| | | } |
| | | |
| | | /** |
| | | * 跳转到session超时页面 |
| | | * |
| | | * @author fengshuonan |
| | | */ |
| | | @RequestMapping(path = "/sessionError") |
| | | public String errorPageInfo(Model model) { |
| | | model.addAttribute("tips", "session超时"); |
| | | return "/login.html"; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.controller; |
| | | |
| | | import org.springframework.web.servlet.View; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 错误页面的默认跳转(例如请求404的时候,默认走这个视图解析器) |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-21 11:34 |
| | | */ |
| | | public class GunsErrorView implements View { |
| | | |
| | | @Override |
| | | public String getContentType() { |
| | | return "text/html"; |
| | | } |
| | | |
| | | @Override |
| | | public void render(Map<String, ?> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { |
| | | httpServletRequest.getRequestDispatcher("/global/error").forward(httpServletRequest, httpServletResponse); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.tips; |
| | | |
| | | /** |
| | | * 返回给前台的错误提示 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月12日 下午5:05:22 |
| | | */ |
| | | public class ErrorTip extends Tip { |
| | | |
| | | public ErrorTip(int code, String message) { |
| | | super(); |
| | | this.code = code; |
| | | this.message = message; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.tips; |
| | | |
| | | /** |
| | | * 返回给前台的成功提示 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年11月12日 下午5:05:22 |
| | | */ |
| | | public class SuccessTip extends Tip { |
| | | |
| | | public SuccessTip(){ |
| | | super.code = 200; |
| | | super.message = "操作成功"; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.tips; |
| | | |
| | | /** |
| | | * 返回给前台的提示(最终转化为json形式) |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017年1月11日 下午11:58:00 |
| | | */ |
| | | public abstract class Tip { |
| | | |
| | | protected int code; |
| | | protected String message; |
| | | |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(int code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.base.warpper; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 控制器查询结果的包装类基类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月13日 下午10:49:36 |
| | | */ |
| | | public abstract class BaseControllerWarpper { |
| | | |
| | | public Object obj = null; |
| | | |
| | | public BaseControllerWarpper(Object obj) { |
| | | this.obj = obj; |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public Object warp() { |
| | | if (this.obj instanceof List) { |
| | | List<Map<String, Object>> list = (List<Map<String, Object>>) this.obj; |
| | | for (Map<String, Object> map : list) { |
| | | warpTheMap(map); |
| | | } |
| | | return list; |
| | | } else if (this.obj instanceof Map) { |
| | | Map<String, Object> map = (Map<String, Object>) this.obj; |
| | | warpTheMap(map); |
| | | return map; |
| | | } else { |
| | | return this.obj; |
| | | } |
| | | } |
| | | |
| | | protected abstract void warpTheMap(Map<String, Object> map); |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | |
| | | /** |
| | | * 缓存工厂基类 |
| | | */ |
| | | public abstract class BaseCacheFactory implements ICache { |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public <T> T get(String cacheName, Object key, ILoader iLoader) { |
| | | Object data = get(cacheName, key); |
| | | if (data == null) { |
| | | data = iLoader.load(); |
| | | put(cacheName, key, data); |
| | | } |
| | | return (T) data; |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass) { |
| | | Object data = get(cacheName, key); |
| | | if (data == null) { |
| | | try { |
| | | ILoader dataLoader = iLoaderClass.newInstance(); |
| | | data = dataLoader.load(); |
| | | put(cacheName, key, data); |
| | | } catch (Exception e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | return (T) data; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 缓存工具类 |
| | | */ |
| | | public class CacheKit { |
| | | |
| | | private static ICache defaultCacheFactory = new EhcacheFactory(); |
| | | |
| | | public static void put(String cacheName, Object key, Object value) { |
| | | defaultCacheFactory.put(cacheName, key, value); |
| | | } |
| | | |
| | | public static <T> T get(String cacheName, Object key) { |
| | | return defaultCacheFactory.get(cacheName, key); |
| | | } |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | public static List getKeys(String cacheName) { |
| | | return defaultCacheFactory.getKeys(cacheName); |
| | | } |
| | | |
| | | public static void remove(String cacheName, Object key) { |
| | | defaultCacheFactory.remove(cacheName, key); |
| | | } |
| | | |
| | | public static void removeAll(String cacheName) { |
| | | defaultCacheFactory.removeAll(cacheName); |
| | | } |
| | | |
| | | public static <T> T get(String cacheName, Object key, ILoader iLoader) { |
| | | return defaultCacheFactory.get(cacheName, key, iLoader); |
| | | } |
| | | |
| | | public static <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass) { |
| | | return defaultCacheFactory.get(cacheName, key, iLoaderClass); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2011-2016, James Zhan 詹波 (jfinal@126.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | import net.sf.ehcache.Cache; |
| | | import net.sf.ehcache.CacheManager; |
| | | import net.sf.ehcache.Element; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * Ehcache缓存工厂 |
| | | */ |
| | | public class EhcacheFactory extends BaseCacheFactory { |
| | | |
| | | private static CacheManager cacheManager; |
| | | private static volatile Object locker = new Object(); |
| | | private static final Logger log = LoggerFactory.getLogger(EhcacheFactory.class); |
| | | |
| | | private static CacheManager getCacheManager() { |
| | | if (cacheManager == null) { |
| | | synchronized (EhcacheFactory.class) { |
| | | if (cacheManager == null) { |
| | | cacheManager = CacheManager.create(); |
| | | } |
| | | } |
| | | } |
| | | return cacheManager; |
| | | } |
| | | |
| | | static Cache getOrAddCache(String cacheName) { |
| | | CacheManager cacheManager = getCacheManager(); |
| | | Cache cache = cacheManager.getCache(cacheName); |
| | | if (cache == null) { |
| | | synchronized(locker) { |
| | | cache = cacheManager.getCache(cacheName); |
| | | if (cache == null) { |
| | | log.warn("无法找到缓存 [" + cacheName + "]的配置, 使用默认配置."); |
| | | cacheManager.addCacheIfAbsent(cacheName); |
| | | cache = cacheManager.getCache(cacheName); |
| | | log.debug("缓存 [" + cacheName + "] 启动."); |
| | | } |
| | | } |
| | | } |
| | | return cache; |
| | | } |
| | | |
| | | public void put(String cacheName, Object key, Object value) { |
| | | getOrAddCache(cacheName).put(new Element(key, value)); |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | public <T> T get(String cacheName, Object key) { |
| | | Element element = getOrAddCache(cacheName).get(key); |
| | | return element != null ? (T)element.getObjectValue() : null; |
| | | } |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | public List getKeys(String cacheName) { |
| | | return getOrAddCache(cacheName).getKeys(); |
| | | } |
| | | |
| | | public void remove(String cacheName, Object key) { |
| | | getOrAddCache(cacheName).remove(key); |
| | | } |
| | | |
| | | public void removeAll(String cacheName) { |
| | | getOrAddCache(cacheName).removeAll(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 通用缓存接口 |
| | | */ |
| | | public interface ICache { |
| | | |
| | | void put(String cacheName, Object key, Object value); |
| | | |
| | | <T> T get(String cacheName, Object key); |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | List getKeys(String cacheName); |
| | | |
| | | void remove(String cacheName, Object key); |
| | | |
| | | void removeAll(String cacheName); |
| | | |
| | | <T> T get(String cacheName, Object key, ILoader iLoader); |
| | | |
| | | <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass); |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.cache; |
| | | |
| | | /** |
| | | * 数据重载 |
| | | */ |
| | | public interface ILoader { |
| | | Object load(); |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config; |
| | | |
| | | import com.alibaba.fastjson.serializer.SerializeConfig; |
| | | import com.alibaba.fastjson.serializer.SerializerFeature; |
| | | import com.alibaba.fastjson.serializer.ToStringSerializer; |
| | | import com.alibaba.fastjson.serializer.ValueFilter; |
| | | import com.alibaba.fastjson.support.config.FastJsonConfig; |
| | | import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.http.MediaType; |
| | | |
| | | import java.math.BigInteger; |
| | | import java.nio.charset.Charset; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * fastjson配置类 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-05-23 22:56 |
| | | */ |
| | | @Configuration("defaultFastjsonConfig") |
| | | @ConditionalOnClass(com.alibaba.fastjson.JSON.class) |
| | | @ConditionalOnMissingBean(FastJsonHttpMessageConverter.class) |
| | | @ConditionalOnWebApplication |
| | | public class DefaultFastjsonConfig { |
| | | |
| | | @Bean |
| | | public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() { |
| | | FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); |
| | | converter.setFastJsonConfig(fastjsonConfig()); |
| | | converter.setSupportedMediaTypes(getSupportedMediaType()); |
| | | return converter; |
| | | } |
| | | |
| | | /** |
| | | * fastjson的配置 |
| | | */ |
| | | public FastJsonConfig fastjsonConfig() { |
| | | FastJsonConfig fastJsonConfig = new FastJsonConfig(); |
| | | fastJsonConfig.setSerializerFeatures( |
| | | SerializerFeature.PrettyFormat, |
| | | SerializerFeature.WriteMapNullValue, |
| | | SerializerFeature.WriteEnumUsingToString |
| | | ); |
| | | fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | ValueFilter valueFilter = new ValueFilter() { |
| | | public Object process(Object o, String s, Object o1) { |
| | | if (null == o1) { |
| | | o1 = ""; |
| | | } |
| | | return o1; |
| | | } |
| | | }; |
| | | fastJsonConfig.setCharset(Charset.forName("utf-8")); |
| | | fastJsonConfig.setSerializeFilters(valueFilter); |
| | | |
| | | //解决Long转json精度丢失的问题 |
| | | SerializeConfig serializeConfig = SerializeConfig.globalInstance; |
| | | serializeConfig.put(BigInteger.class, ToStringSerializer.instance); |
| | | serializeConfig.put(Long.class, ToStringSerializer.instance); |
| | | serializeConfig.put(Long.TYPE, ToStringSerializer.instance); |
| | | fastJsonConfig.setSerializeConfig(serializeConfig); |
| | | return fastJsonConfig; |
| | | } |
| | | |
| | | /** |
| | | * 支持的mediaType类型 |
| | | */ |
| | | public List<MediaType> getSupportedMediaType() { |
| | | ArrayList<MediaType> mediaTypes = new ArrayList<>(); |
| | | mediaTypes.add(MediaType.APPLICATION_JSON_UTF8); |
| | | return mediaTypes; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config; |
| | | |
| | | import com.stylefeng.guns.core.mutidatasource.aop.MultiSourceExAop; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | /** |
| | | * 多数据源配置 |
| | | * |
| | | * @author stylefeng |
| | | * @Date 2017/5/20 21:58 |
| | | */ |
| | | @Configuration |
| | | @ConditionalOnProperty(prefix = "guns", name = "muti-datasource-open", havingValue = "true") |
| | | public class DefaultMultiConfig { |
| | | |
| | | @Bean |
| | | public MultiSourceExAop multiSourceExAop() { |
| | | return new MultiSourceExAop(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config; |
| | | |
| | | import com.stylefeng.guns.core.config.properties.DruidProperties; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.context.annotation.PropertySource; |
| | | |
| | | /** |
| | | * 默认的配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2018-01-07 12:33 |
| | | */ |
| | | @Configuration |
| | | @PropertySource("classpath:/default-config.properties") |
| | | public class DefaultProperties { |
| | | |
| | | @Bean |
| | | @ConfigurationProperties(prefix = "spring.datasource") |
| | | public DruidProperties druidProperties() { |
| | | return new DruidProperties(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config; |
| | | |
| | | import com.stylefeng.guns.core.base.controller.GunsErrorView; |
| | | import com.stylefeng.guns.core.exception.GunsException; |
| | | import com.stylefeng.guns.core.exception.GunsExceptionEnum; |
| | | import com.stylefeng.guns.core.util.DateUtil; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.core.convert.converter.Converter; |
| | | import org.springframework.core.convert.support.GenericConversionService; |
| | | import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; |
| | | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; |
| | | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; |
| | | |
| | | import javax.annotation.PostConstruct; |
| | | import java.util.Date; |
| | | import java.util.regex.Pattern; |
| | | |
| | | @Configuration |
| | | public class DefaultWebConfig extends WebMvcConfigurationSupport { |
| | | |
| | | @Autowired |
| | | private RequestMappingHandlerAdapter handlerAdapter; |
| | | |
| | | @Bean("error") |
| | | public GunsErrorView error() { |
| | | return new GunsErrorView(); |
| | | } |
| | | |
| | | @PostConstruct |
| | | public void addConversionConfig() { |
| | | ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) handlerAdapter.getWebBindingInitializer(); |
| | | GenericConversionService genericConversionService = (GenericConversionService) initializer.getConversionService(); |
| | | genericConversionService.addConverter(new StringToDateConverter()); |
| | | } |
| | | |
| | | public class StringToDateConverter implements Converter<String, Date> { |
| | | |
| | | @Override |
| | | public Date convert(String dateString) { |
| | | |
| | | String patternDate = "\\d{4}-\\d{1,2}-\\d{1,2}"; |
| | | String patternTimeMinutes = "\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}"; |
| | | String patternTimeSeconds = "\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}"; |
| | | |
| | | boolean dateFlag = Pattern.matches(patternDate, dateString); |
| | | boolean timeMinutesFlag = Pattern.matches(patternTimeMinutes, dateString); |
| | | boolean timeSecondsFlag = Pattern.matches(patternTimeSeconds, dateString); |
| | | |
| | | if (dateFlag) { |
| | | return DateUtil.parseDate(dateString); |
| | | } else if (timeMinutesFlag) { |
| | | return DateUtil.parseTimeMinutes(dateString); |
| | | } else if (timeSecondsFlag) { |
| | | return DateUtil.parseTime(dateString); |
| | | } else { |
| | | throw new GunsException(GunsExceptionEnum.INVLIDE_DATE_STRING); |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
New file |
| | |
| | | package com.stylefeng.guns.core.config.properties; |
| | | |
| | | import com.alibaba.druid.pool.DruidDataSource; |
| | | |
| | | import java.sql.SQLException; |
| | | |
| | | /** |
| | | * <p>数据库数据源配置</p> |
| | | * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在"application.yml"中配置即可</p> |
| | | * @author stylefeng |
| | | * @date 2017-05-21 11:18 |
| | | */ |
| | | public class DruidProperties { |
| | | |
| | | private String url = "jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull"; |
| | | |
| | | private String username = "root"; |
| | | |
| | | private String password = "root"; |
| | | |
| | | private String driverClassName = "com.mysql.cj.jdbc.Driver"; |
| | | |
| | | private Integer initialSize = 2; |
| | | |
| | | private Integer minIdle = 1; |
| | | |
| | | private Integer maxActive = 20; |
| | | |
| | | private Integer maxWait = 60000; |
| | | |
| | | private Integer timeBetweenEvictionRunsMillis = 60000; |
| | | |
| | | private Integer minEvictableIdleTimeMillis = 300000; |
| | | |
| | | private String validationQuery = "SELECT 'x'"; |
| | | |
| | | private Boolean testWhileIdle = true; |
| | | |
| | | private Boolean testOnBorrow = false; |
| | | |
| | | private Boolean testOnReturn = false; |
| | | |
| | | private Boolean poolPreparedStatements = true; |
| | | |
| | | private Integer maxPoolPreparedStatementPerConnectionSize = 20; |
| | | |
| | | private String filters = "stat"; |
| | | |
| | | public void config(DruidDataSource dataSource) { |
| | | |
| | | dataSource.setUrl(url); |
| | | dataSource.setUsername(username); |
| | | dataSource.setPassword(password); |
| | | |
| | | dataSource.setDriverClassName(driverClassName); |
| | | dataSource.setInitialSize(initialSize); //定义初始连接数 |
| | | dataSource.setMinIdle(minIdle); //最小空闲 |
| | | dataSource.setMaxActive(maxActive); //定义最大连接数 |
| | | dataSource.setMaxWait(maxWait); //最长等待时间 |
| | | |
| | | // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 |
| | | dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); |
| | | |
| | | // 配置一个连接在池中最小生存的时间,单位是毫秒 |
| | | dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); |
| | | dataSource.setValidationQuery(validationQuery); |
| | | dataSource.setTestWhileIdle(testWhileIdle); |
| | | dataSource.setTestOnBorrow(testOnBorrow); |
| | | dataSource.setTestOnReturn(testOnReturn); |
| | | |
| | | // 打开PSCache,并且指定每个连接上PSCache的大小 |
| | | dataSource.setPoolPreparedStatements(poolPreparedStatements); |
| | | dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); |
| | | |
| | | try { |
| | | dataSource.setFilters(filters); |
| | | } catch (SQLException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public String getUsername() { |
| | | return username; |
| | | } |
| | | |
| | | public void setUsername(String username) { |
| | | this.username = username; |
| | | } |
| | | |
| | | public String getPassword() { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) { |
| | | this.password = password; |
| | | } |
| | | |
| | | public String getDriverClassName() { |
| | | return driverClassName; |
| | | } |
| | | |
| | | public void setDriverClassName(String driverClassName) { |
| | | this.driverClassName = driverClassName; |
| | | } |
| | | |
| | | public Integer getInitialSize() { |
| | | return initialSize; |
| | | } |
| | | |
| | | public void setInitialSize(Integer initialSize) { |
| | | this.initialSize = initialSize; |
| | | } |
| | | |
| | | public Integer getMinIdle() { |
| | | return minIdle; |
| | | } |
| | | |
| | | public void setMinIdle(Integer minIdle) { |
| | | this.minIdle = minIdle; |
| | | } |
| | | |
| | | public Integer getMaxActive() { |
| | | return maxActive; |
| | | } |
| | | |
| | | public void setMaxActive(Integer maxActive) { |
| | | this.maxActive = maxActive; |
| | | } |
| | | |
| | | public Integer getMaxWait() { |
| | | return maxWait; |
| | | } |
| | | |
| | | public void setMaxWait(Integer maxWait) { |
| | | this.maxWait = maxWait; |
| | | } |
| | | |
| | | public Integer getTimeBetweenEvictionRunsMillis() { |
| | | return timeBetweenEvictionRunsMillis; |
| | | } |
| | | |
| | | public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) { |
| | | this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; |
| | | } |
| | | |
| | | public Integer getMinEvictableIdleTimeMillis() { |
| | | return minEvictableIdleTimeMillis; |
| | | } |
| | | |
| | | public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) { |
| | | this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; |
| | | } |
| | | |
| | | public String getValidationQuery() { |
| | | return validationQuery; |
| | | } |
| | | |
| | | public void setValidationQuery(String validationQuery) { |
| | | this.validationQuery = validationQuery; |
| | | } |
| | | |
| | | public Boolean getTestWhileIdle() { |
| | | return testWhileIdle; |
| | | } |
| | | |
| | | public void setTestWhileIdle(Boolean testWhileIdle) { |
| | | this.testWhileIdle = testWhileIdle; |
| | | } |
| | | |
| | | public Boolean getTestOnBorrow() { |
| | | return testOnBorrow; |
| | | } |
| | | |
| | | public void setTestOnBorrow(Boolean testOnBorrow) { |
| | | this.testOnBorrow = testOnBorrow; |
| | | } |
| | | |
| | | public Boolean getTestOnReturn() { |
| | | return testOnReturn; |
| | | } |
| | | |
| | | public void setTestOnReturn(Boolean testOnReturn) { |
| | | this.testOnReturn = testOnReturn; |
| | | } |
| | | |
| | | public Boolean getPoolPreparedStatements() { |
| | | return poolPreparedStatements; |
| | | } |
| | | |
| | | public void setPoolPreparedStatements(Boolean poolPreparedStatements) { |
| | | this.poolPreparedStatements = poolPreparedStatements; |
| | | } |
| | | |
| | | public Integer getMaxPoolPreparedStatementPerConnectionSize() { |
| | | return maxPoolPreparedStatementPerConnectionSize; |
| | | } |
| | | |
| | | public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) { |
| | | this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; |
| | | } |
| | | |
| | | public String getFilters() { |
| | | return filters; |
| | | } |
| | | |
| | | public void setFilters(String filters) { |
| | | this.filters = filters; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.config.properties; |
| | | |
| | | import com.alibaba.druid.pool.DruidDataSource; |
| | | |
| | | /** |
| | | * 默认多数据源配置 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-08-16 10:02 |
| | | */ |
| | | public class MutiDataSourceProperties { |
| | | |
| | | private String url = "jdbc:mysql://127.0.0.1:3306/biz?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull"; |
| | | |
| | | private String username = "root"; |
| | | |
| | | private String password = "root"; |
| | | |
| | | private String driverClassName = "com.mysql.cj.jdbc.Driver"; |
| | | |
| | | private String validationQuery = "SELECT 'x'"; |
| | | |
| | | private String[] dataSourceNames = {"dataSourceGuns", "dataSourceBiz"}; |
| | | |
| | | public void config(DruidDataSource dataSource) { |
| | | dataSource.setUrl(url); |
| | | dataSource.setUsername(username); |
| | | dataSource.setPassword(password); |
| | | dataSource.setDriverClassName(driverClassName); |
| | | dataSource.setValidationQuery(validationQuery); |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public String getUsername() { |
| | | return username; |
| | | } |
| | | |
| | | public void setUsername(String username) { |
| | | this.username = username; |
| | | } |
| | | |
| | | public String getPassword() { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) { |
| | | this.password = password; |
| | | } |
| | | |
| | | public String getDriverClassName() { |
| | | return driverClassName; |
| | | } |
| | | |
| | | public void setDriverClassName(String driverClassName) { |
| | | this.driverClassName = driverClassName; |
| | | } |
| | | |
| | | public String getValidationQuery() { |
| | | return validationQuery; |
| | | } |
| | | |
| | | public void setValidationQuery(String validationQuery) { |
| | | this.validationQuery = validationQuery; |
| | | } |
| | | |
| | | public String[] getDataSourceNames() { |
| | | return dataSourceNames; |
| | | } |
| | | |
| | | public void setDataSourceNames(String[] dataSourceNames) { |
| | | this.dataSourceNames = dataSourceNames; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.constant; |
| | | |
| | | /** |
| | | * 是否是菜单的枚举 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年6月1日22:50:11 |
| | | */ |
| | | public enum IsMenu { |
| | | |
| | | YES(1, "是"), |
| | | NO(0, "不是"); //不是菜单的是按钮 |
| | | |
| | | int code; |
| | | String message; |
| | | |
| | | IsMenu(int code, String message) { |
| | | this.code = code; |
| | | this.message = message; |
| | | } |
| | | |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(int code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | |
| | | public static String valueOf(Integer status) { |
| | | if (status == null) { |
| | | return ""; |
| | | } else { |
| | | for (IsMenu s : IsMenu.values()) { |
| | | if (s.getCode() == status) { |
| | | return s.getMessage(); |
| | | } |
| | | } |
| | | return ""; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.datascope; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 数据范围 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-07-23 22:19 |
| | | */ |
| | | public class DataScope { |
| | | |
| | | /** |
| | | * 限制范围的字段名称 |
| | | */ |
| | | private String scopeName = "deptid"; |
| | | |
| | | /** |
| | | * 具体的数据范围 |
| | | */ |
| | | private List<Integer> deptIds; |
| | | |
| | | public DataScope() { |
| | | } |
| | | |
| | | public DataScope(List<Integer> deptIds) { |
| | | this.deptIds = deptIds; |
| | | } |
| | | |
| | | public DataScope(String scopeName, List<Integer> deptIds) { |
| | | this.scopeName = scopeName; |
| | | this.deptIds = deptIds; |
| | | } |
| | | |
| | | public List<Integer> getDeptIds() { |
| | | return deptIds; |
| | | } |
| | | |
| | | public void setDeptIds(List<Integer> deptIds) { |
| | | this.deptIds = deptIds; |
| | | } |
| | | |
| | | public String getScopeName() { |
| | | return scopeName; |
| | | } |
| | | |
| | | public void setScopeName(String scopeName) { |
| | | this.scopeName = scopeName; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.datascope; |
| | | |
| | | |
| | | import com.baomidou.mybatisplus.toolkit.PluginUtils; |
| | | import com.stylefeng.guns.core.support.CollectionKit; |
| | | import org.apache.ibatis.executor.statement.StatementHandler; |
| | | import org.apache.ibatis.mapping.BoundSql; |
| | | import org.apache.ibatis.mapping.MappedStatement; |
| | | import org.apache.ibatis.mapping.SqlCommandType; |
| | | import org.apache.ibatis.plugin.*; |
| | | import org.apache.ibatis.reflection.MetaObject; |
| | | import org.apache.ibatis.reflection.SystemMetaObject; |
| | | |
| | | import java.sql.Connection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Properties; |
| | | |
| | | /** |
| | | * 数据范围的拦截器 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-07-23 21:26 |
| | | */ |
| | | @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) |
| | | public class DataScopeInterceptor implements Interceptor { |
| | | |
| | | @Override |
| | | public Object intercept(Invocation invocation) throws Throwable { |
| | | StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget()); |
| | | MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); |
| | | MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); |
| | | |
| | | if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) { |
| | | return invocation.proceed(); |
| | | } |
| | | |
| | | BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); |
| | | String originalSql = boundSql.getSql(); |
| | | Object parameterObject = boundSql.getParameterObject(); |
| | | |
| | | //查找参数中包含DataScope类型的参数 |
| | | DataScope dataScope = findDataScopeObject(parameterObject); |
| | | |
| | | if (dataScope == null) { |
| | | return invocation.proceed(); |
| | | } else { |
| | | String scopeName = dataScope.getScopeName(); |
| | | List<Integer> deptIds = dataScope.getDeptIds(); |
| | | String join = CollectionKit.join(deptIds, ","); |
| | | originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")"; |
| | | metaStatementHandler.setValue("delegate.boundSql.sql", originalSql); |
| | | return invocation.proceed(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 查找参数是否包括DataScope对象 |
| | | */ |
| | | public DataScope findDataScopeObject(Object parameterObj) { |
| | | if (parameterObj instanceof DataScope) { |
| | | return (DataScope) parameterObj; |
| | | } else if (parameterObj instanceof Map) { |
| | | for (Object val : ((Map<?, ?>) parameterObj).values()) { |
| | | if (val instanceof DataScope) { |
| | | return (DataScope) val; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public Object plugin(Object target) { |
| | | return Plugin.wrap(target, this); |
| | | } |
| | | |
| | | @Override |
| | | public void setProperties(Properties properties) { |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.db; |
| | | |
| | | import com.baomidou.mybatisplus.mapper.BaseMapper; |
| | | import com.stylefeng.guns.core.util.SpringContextHolder; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | | * 便捷数据库操作类 |
| | | * <p> |
| | | * <p> |
| | | * 本类的使用情景: |
| | | * <p> |
| | | * 1.单纯想创建现有的Mapper |
| | | * <p>例如: |
| | | * Db.getMapper(UserLoginMapper.class).selectById("14779707158513204");<br> |
| | | * <p> |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月22日 下午8:07:17 |
| | | */ |
| | | @SuppressWarnings("all") |
| | | public class Db<T> { |
| | | |
| | | /** |
| | | * 每个Db类,包装一个Mapper接口,这个clazz就是接口的类类型,例如UserMapper.class |
| | | */ |
| | | private Class<T> clazz; |
| | | |
| | | /** |
| | | * Mapper的父类接口 |
| | | */ |
| | | private BaseMapper<?> baseMapper; |
| | | |
| | | /** |
| | | * 私有构造方法,不允许自己创建 |
| | | */ |
| | | private Db(Class clazz) { |
| | | this.clazz = clazz; |
| | | this.baseMapper = (BaseMapper<?>) SpringContextHolder.getBean(clazz); |
| | | } |
| | | |
| | | /** |
| | | * <p> |
| | | * 创建包含指定mapper的Db工具类,使用本类的第一种用法 |
| | | * |
| | | * @param clazz mapper的类类型 |
| | | * @date 2017年2月22日 下午10:09:31 |
| | | */ |
| | | public static <T> Db<T> create(Class<T> clazz) { |
| | | return new Db<T>(clazz); |
| | | } |
| | | |
| | | /** |
| | | * <p> |
| | | * 获取一个mapper的快捷方法 |
| | | * |
| | | * @param clazz mapper类的类对象 |
| | | * @date 2017年2月22日 下午10:31:35 |
| | | */ |
| | | public BaseMapper<?> getMapper() { |
| | | return this.baseMapper; |
| | | } |
| | | |
| | | /** |
| | | * <p> |
| | | * 获取一个mapper的快捷方法 |
| | | * |
| | | * @param clazz mapper类的类对象 |
| | | * @date 2017年2月22日 下午10:31:35 |
| | | */ |
| | | public static <T> T getMapper(Class<T> clazz) { |
| | | return SpringContextHolder.getBean(clazz); |
| | | } |
| | | |
| | | /** |
| | | * 通过一个条件获取数据库中的一条记录(会返回null) |
| | | * |
| | | * @date 2017年2月22日 下午10:45:51 |
| | | */ |
| | | public <E> E selectOneByCon(String condition, Object value) { |
| | | List<?> results = selectOneByConList(condition, value); |
| | | if (results != null && results.size() > 0) { |
| | | return (E) results.get(0); |
| | | } else { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 通过一个条件获取一堆记录(会返回null) |
| | | * |
| | | * @date 2017年2月22日 下午10:45:51 |
| | | */ |
| | | public <E> List<E> selectOneByConList(String condition, Object value) { |
| | | HashMap<String, Object> conditionMap = new HashMap<String, Object>(); |
| | | conditionMap.put(condition, value); |
| | | |
| | | List<E> results = (List<E>) this.baseMapper.selectByMap(conditionMap); |
| | | if (results == null || results.size() == 0) { |
| | | return null; |
| | | } else { |
| | | return results; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.exception; |
| | | |
| | | /** |
| | | * 封装guns的异常 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/12/28 下午10:32 |
| | | */ |
| | | public class GunsException extends RuntimeException { |
| | | |
| | | private Integer code; |
| | | |
| | | private String message; |
| | | |
| | | public GunsException(ServiceExceptionEnum serviceExceptionEnum) { |
| | | this.code = serviceExceptionEnum.getCode(); |
| | | this.message = serviceExceptionEnum.getMessage(); |
| | | } |
| | | |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(Integer code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | @Override |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.exception; |
| | | |
| | | /** |
| | | * Guns异常枚举 |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017/12/28 下午10:33 |
| | | */ |
| | | public enum GunsExceptionEnum implements ServiceExceptionEnum { |
| | | |
| | | /** |
| | | * 其他 |
| | | */ |
| | | INVLIDE_DATE_STRING(400, "输入日期格式不对"), |
| | | |
| | | /** |
| | | * 其他 |
| | | */ |
| | | WRITE_ERROR(500, "渲染界面错误"), |
| | | |
| | | /** |
| | | * 文件上传 |
| | | */ |
| | | FILE_READING_ERROR(400, "FILE_READING_ERROR!"), |
| | | FILE_NOT_FOUND(400, "FILE_NOT_FOUND!"), |
| | | |
| | | /** |
| | | * 错误的请求 |
| | | */ |
| | | REQUEST_NULL(400, "请求有错误"), |
| | | SERVER_ERROR(500, "服务器异常"); |
| | | |
| | | GunsExceptionEnum(int code, String message) { |
| | | this.code = code; |
| | | this.message = message; |
| | | } |
| | | |
| | | private Integer code; |
| | | |
| | | private String message; |
| | | |
| | | @Override |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(Integer code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | @Override |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.exception; |
| | | |
| | | /** |
| | | * 抽象接口 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017-12-28-下午10:27 |
| | | */ |
| | | public interface ServiceExceptionEnum { |
| | | |
| | | /** |
| | | * 获取异常编码 |
| | | */ |
| | | Integer getCode(); |
| | | |
| | | /** |
| | | * 获取异常信息 |
| | | */ |
| | | String getMessage(); |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.mutidatasource; |
| | | |
| | | /** |
| | | * datasource的上下文 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年3月5日 上午9:10:58 |
| | | */ |
| | | public class DataSourceContextHolder { |
| | | |
| | | private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); |
| | | |
| | | /** |
| | | * 设置数据源类型 |
| | | * |
| | | * @param dataSourceType 数据库类型 |
| | | */ |
| | | public static void setDataSourceType(String dataSourceType) { |
| | | contextHolder.set(dataSourceType); |
| | | } |
| | | |
| | | /** |
| | | * 获取数据源类型 |
| | | */ |
| | | public static String getDataSourceType() { |
| | | return contextHolder.get(); |
| | | } |
| | | |
| | | /** |
| | | * 清除数据源类型 |
| | | */ |
| | | public static void clearDataSourceType() { |
| | | contextHolder.remove(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.mutidatasource; |
| | | |
| | | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; |
| | | |
| | | /** |
| | | * 动态数据源 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年3月5日 上午9:11:49 |
| | | */ |
| | | public class DynamicDataSource extends AbstractRoutingDataSource { |
| | | |
| | | @Override |
| | | protected Object determineCurrentLookupKey() { |
| | | return DataSourceContextHolder.getDataSourceType(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.mutidatasource.annotion; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * |
| | | * 多数据源标识 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年3月5日 上午9:44:24 |
| | | */ |
| | | @Inherited |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Target({ ElementType.METHOD }) |
| | | public @interface DataSource { |
| | | |
| | | String name() default ""; |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.mutidatasource.aop; |
| | | |
| | | import com.stylefeng.guns.core.mutidatasource.DataSourceContextHolder; |
| | | import com.stylefeng.guns.core.mutidatasource.annotion.DataSource; |
| | | import com.stylefeng.guns.core.config.properties.MutiDataSourceProperties; |
| | | import org.aspectj.lang.ProceedingJoinPoint; |
| | | import org.aspectj.lang.Signature; |
| | | import org.aspectj.lang.annotation.Around; |
| | | import org.aspectj.lang.annotation.Aspect; |
| | | import org.aspectj.lang.annotation.Pointcut; |
| | | import org.aspectj.lang.reflect.MethodSignature; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.core.Ordered; |
| | | |
| | | import java.lang.reflect.Method; |
| | | |
| | | /** |
| | | * 多数据源切换的aop |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年3月5日 上午10:22:16 |
| | | */ |
| | | @Aspect |
| | | public class MultiSourceExAop implements Ordered { |
| | | |
| | | private Logger log = LoggerFactory.getLogger(this.getClass()); |
| | | |
| | | @Autowired |
| | | MutiDataSourceProperties mutiDataSourceProperties; |
| | | |
| | | @Pointcut(value = "@annotation(com.stylefeng.guns.core.mutidatasource.annotion.DataSource)") |
| | | private void cut() { |
| | | |
| | | } |
| | | |
| | | @Around("cut()") |
| | | public Object around(ProceedingJoinPoint point) throws Throwable { |
| | | |
| | | Signature signature = point.getSignature(); |
| | | MethodSignature methodSignature = null; |
| | | if (!(signature instanceof MethodSignature)) { |
| | | throw new IllegalArgumentException("该注解只能用于方法"); |
| | | } |
| | | methodSignature = (MethodSignature) signature; |
| | | |
| | | Object target = point.getTarget(); |
| | | Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes()); |
| | | |
| | | DataSource datasource = currentMethod.getAnnotation(DataSource.class); |
| | | if (datasource != null) { |
| | | DataSourceContextHolder.setDataSourceType(datasource.name()); |
| | | log.debug("设置数据源为:" + datasource.name()); |
| | | } else { |
| | | DataSourceContextHolder.setDataSourceType(mutiDataSourceProperties.getDataSourceNames()[0]); |
| | | log.debug("设置数据源为:dataSourceCurrent"); |
| | | } |
| | | |
| | | try { |
| | | return point.proceed(); |
| | | } finally { |
| | | log.debug("清空数据源信息!"); |
| | | DataSourceContextHolder.clearDataSourceType(); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * aop的顺序要早于spring的事务 |
| | | */ |
| | | @Override |
| | | public int getOrder() { |
| | | return 1; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.node; |
| | | |
| | | import com.stylefeng.guns.core.constant.IsMenu; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * @author fengshuonan |
| | | * @Description 菜单的节点 |
| | | * @date 2016年12月6日 上午11:34:17 |
| | | */ |
| | | public class MenuNode implements Comparable { |
| | | |
| | | /** |
| | | * 节点id |
| | | */ |
| | | private Long id; |
| | | |
| | | /** |
| | | * 父节点 |
| | | */ |
| | | private Long parentId; |
| | | |
| | | /** |
| | | * 节点名称 |
| | | */ |
| | | private String name; |
| | | |
| | | /** |
| | | * 按钮级别 |
| | | */ |
| | | private Integer levels; |
| | | |
| | | /** |
| | | * 按钮级别 |
| | | */ |
| | | private Integer ismenu; |
| | | |
| | | /** |
| | | * 按钮的排序 |
| | | */ |
| | | private Integer num; |
| | | |
| | | /** |
| | | * 节点的url |
| | | */ |
| | | private String url; |
| | | |
| | | /** |
| | | * 节点图标 |
| | | */ |
| | | private String icon; |
| | | |
| | | /** |
| | | * 子节点的集合 |
| | | */ |
| | | private List<MenuNode> children; |
| | | |
| | | /** |
| | | * 查询子节点时候的临时集合 |
| | | */ |
| | | private List<MenuNode> linkedList = new ArrayList<MenuNode>(); |
| | | |
| | | public MenuNode() { |
| | | super(); |
| | | } |
| | | |
| | | public MenuNode(Long id, Long parentId) { |
| | | super(); |
| | | this.id = id; |
| | | this.parentId = parentId; |
| | | } |
| | | |
| | | public Integer getLevels() { |
| | | return levels; |
| | | } |
| | | |
| | | public void setLevels(Integer levels) { |
| | | this.levels = levels; |
| | | } |
| | | |
| | | public String getIcon() { |
| | | return icon; |
| | | } |
| | | |
| | | public void setIcon(String icon) { |
| | | this.icon = icon; |
| | | } |
| | | |
| | | public static MenuNode createRoot() { |
| | | return new MenuNode(0L, -1L); |
| | | } |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public Long getParentId() { |
| | | return parentId; |
| | | } |
| | | |
| | | public void setParentId(Long parentId) { |
| | | this.parentId = parentId; |
| | | } |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public List<MenuNode> getChildren() { |
| | | return children; |
| | | } |
| | | |
| | | public void setChildren(List<MenuNode> children) { |
| | | this.children = children; |
| | | } |
| | | |
| | | public Integer getNum() { |
| | | return num; |
| | | } |
| | | |
| | | public void setNum(Integer num) { |
| | | this.num = num; |
| | | } |
| | | |
| | | public Integer getIsmenu() { |
| | | return ismenu; |
| | | } |
| | | |
| | | public void setIsmenu(Integer ismenu) { |
| | | this.ismenu = ismenu; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "MenuNode{" + |
| | | "id=" + id + |
| | | ", parentId=" + parentId + |
| | | ", name='" + name + '\'' + |
| | | ", levels=" + levels + |
| | | ", num=" + num + |
| | | ", url='" + url + '\'' + |
| | | ", icon='" + icon + '\'' + |
| | | ", children=" + children + |
| | | ", linkedList=" + linkedList + |
| | | '}'; |
| | | } |
| | | |
| | | /** |
| | | * 重写排序比较接口,首先根据等级排序,然后更具排序字段排序 |
| | | * |
| | | * @param o |
| | | * @return |
| | | */ |
| | | @Override |
| | | public int compareTo(Object o) { |
| | | MenuNode menuNode = (MenuNode) o; |
| | | Integer num = menuNode.getNum(); |
| | | Integer levels = menuNode.getLevels(); |
| | | if (num == null) { |
| | | num = 0; |
| | | } |
| | | if (levels == null) { |
| | | levels = 0; |
| | | } |
| | | if (this.levels.compareTo(levels) == 0) { |
| | | return this.num.compareTo(num); |
| | | } else { |
| | | return this.levels.compareTo(levels); |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 构建页面菜单列表 |
| | | */ |
| | | public static List<MenuNode> buildTitle(List<MenuNode> nodes) { |
| | | if (nodes.size() <= 0) { |
| | | return nodes; |
| | | } |
| | | //剔除非菜单 |
| | | nodes.removeIf(node -> node.getIsmenu() != IsMenu.YES.getCode()); |
| | | //对菜单排序,返回列表按菜单等级,序号的排序方式排列 |
| | | Collections.sort(nodes); |
| | | return mergeList(nodes, nodes.get(nodes.size() - 1).getLevels(), null); |
| | | } |
| | | |
| | | /** |
| | | * 递归合并数组为子数组,最后返回第一层 |
| | | * |
| | | * @param menuList |
| | | * @param listMap |
| | | * @return |
| | | */ |
| | | private static List<MenuNode> mergeList(List<MenuNode> menuList, int rank, Map<Long, List<MenuNode>> listMap) { |
| | | //保存当次调用总共合并了多少元素 |
| | | int n; |
| | | //保存当次调用总共合并出来的list |
| | | Map<Long, List<MenuNode>> currentMap = new HashMap<>(); |
| | | //由于按等级从小到大排序,需要从后往前排序 |
| | | //判断该节点是否属于当前循环的等级,不等于则跳出循环 |
| | | for (n = menuList.size() - 1; n >=0&&menuList.get(n).getLevels() == rank; n--) { |
| | | //判断之前的调用是否有返回以该节点的id为key的map,有则设置为children列表。 |
| | | if (listMap != null && listMap.get(menuList.get(n).getId()) != null) { |
| | | menuList.get(n).setChildren(listMap.get(menuList.get(n).getId())); |
| | | } |
| | | if (menuList.get(n).getParentId()!=null&&menuList.get(n).getParentId()!=0) { |
| | | //判断当前节点所属的pid是否已经创建了以该pid为key的键值对,没有则创建新的链表 |
| | | currentMap.computeIfAbsent(menuList.get(n).getParentId(), k -> new LinkedList<>()); |
| | | //将该节点插入到对应的list的头部 |
| | | currentMap.get(menuList.get(n).getParentId()).add(0, menuList.get(n)); |
| | | } |
| | | } |
| | | if (n <0) { |
| | | return menuList; |
| | | } else { |
| | | return mergeList(menuList.subList(0, n+1), menuList.get(n).getLevels(), currentMap); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.node; |
| | | |
| | | /** |
| | | * |
| | | * jquery ztree 插件的节点 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年2月17日 下午8:25:14 |
| | | */ |
| | | public class ZTreeNode { |
| | | |
| | | private Long id; //节点id |
| | | |
| | | private Long pId;//父节点id |
| | | |
| | | private String name;//节点名称 |
| | | |
| | | private Boolean open;//是否打开节点 |
| | | |
| | | private Boolean checked;//是否被选中 |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public Long getpId() { |
| | | return pId; |
| | | } |
| | | |
| | | public void setpId(Long pId) { |
| | | this.pId = pId; |
| | | } |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public Boolean getOpen() { |
| | | return open; |
| | | } |
| | | |
| | | public void setOpen(Boolean open) { |
| | | this.open = open; |
| | | } |
| | | |
| | | public Boolean getIsOpen() { |
| | | return open; |
| | | } |
| | | |
| | | public void setIsOpen(Boolean open) { |
| | | this.open = open; |
| | | } |
| | | |
| | | public Boolean getChecked() { |
| | | return checked; |
| | | } |
| | | |
| | | public void setChecked(Boolean checked) { |
| | | this.checked = checked; |
| | | } |
| | | |
| | | public static ZTreeNode createParent(){ |
| | | ZTreeNode zTreeNode = new ZTreeNode(); |
| | | zTreeNode.setChecked(true); |
| | | zTreeNode.setId(0L); |
| | | zTreeNode.setName("顶级"); |
| | | zTreeNode.setOpen(true); |
| | | zTreeNode.setpId(0L); |
| | | return zTreeNode; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.page; |
| | | |
| | | /** |
| | | * 分页参数类(for BootStrap Table) |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2017年1月21日 下午2:21:35 |
| | | */ |
| | | public class PageBT { |
| | | |
| | | private int limit; // 每页显示个数 |
| | | |
| | | private int offset; // 查询的偏移量(查询的页数 = offset/limit + 1) |
| | | |
| | | private String order; // 排序方式 |
| | | |
| | | |
| | | public PageBT() { |
| | | super(); |
| | | } |
| | | |
| | | public PageBT(int limit, int offset) { |
| | | super(); |
| | | this.limit = limit; |
| | | this.offset = offset; |
| | | } |
| | | |
| | | public int getLimit() { |
| | | return limit; |
| | | } |
| | | |
| | | public void setLimit(int limit) { |
| | | this.limit = limit; |
| | | } |
| | | |
| | | public int getOffset() { |
| | | return offset; |
| | | } |
| | | |
| | | public void setOffset(int offset) { |
| | | this.offset = offset; |
| | | } |
| | | |
| | | public String getOrder() { |
| | | return order; |
| | | } |
| | | |
| | | public void setOrder(String order) { |
| | | this.order = order; |
| | | } |
| | | |
| | | public int getPageSize() { |
| | | return this.limit; |
| | | } |
| | | |
| | | public int getPageNumber() { |
| | | return this.offset / this.limit + 1; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "PageBT [limit=" + limit + ", offset=" + offset + ", order=" + order + "]"; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.page; |
| | | |
| | | import com.baomidou.mybatisplus.plugins.Page; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 分页结果的封装(for Bootstrap Table) |
| | | * |
| | | * @author fengshuonan |
| | | * @Date 2017年1月22日 下午11:06:41 |
| | | */ |
| | | public class PageInfoBT<T> { |
| | | |
| | | // 结果集 |
| | | private List<T> rows; |
| | | |
| | | // 总数 |
| | | private long total; |
| | | |
| | | public PageInfoBT(Page<T> page) { |
| | | this.rows = page.getRecords(); |
| | | this.total = page.getTotal(); |
| | | } |
| | | |
| | | public List<T> getRows() { |
| | | return rows; |
| | | } |
| | | |
| | | public void setRows(List<T> rows) { |
| | | this.rows = rows; |
| | | } |
| | | |
| | | public long getTotal() { |
| | | return total; |
| | | } |
| | | |
| | | public void setTotal(long total) { |
| | | this.total = total; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.qr; |
| | | |
| | | import com.google.zxing.BarcodeFormat; |
| | | import com.google.zxing.EncodeHintType; |
| | | import com.google.zxing.MultiFormatWriter; |
| | | import com.google.zxing.WriterException; |
| | | import com.google.zxing.common.BitMatrix; |
| | | import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import javax.imageio.ImageIO; |
| | | import java.awt.*; |
| | | import java.awt.geom.AffineTransform; |
| | | import java.awt.image.AffineTransformOp; |
| | | import java.awt.image.BufferedImage; |
| | | import java.io.File; |
| | | import java.io.FileOutputStream; |
| | | import java.io.IOException; |
| | | import java.io.OutputStream; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 内嵌图片的二维码生成器 |
| | | * |
| | | * @author lichunxi |
| | | */ |
| | | public class ImgQrTool { |
| | | |
| | | private static Logger log = LoggerFactory.getLogger(ImgQrTool.class); |
| | | |
| | | // 镶嵌的图片宽度的一般 |
| | | private static final int IMAGE_WIDTH = 80; |
| | | private static final int IMAGE_HEIGHT = 80; |
| | | private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2; |
| | | private static final int FRAME_WIDTH = 2; |
| | | |
| | | // 二维码写码器 |
| | | private static MultiFormatWriter mutiWriter = new MultiFormatWriter(); |
| | | |
| | | /** |
| | | * 生成带图片的二维码 |
| | | * |
| | | * @param content 二维码的内容 |
| | | * @param width 宽度 |
| | | * @param height 高度 |
| | | * @param srcImagePath 被镶嵌的图片的地址 |
| | | * @param destImagePath 生成二维码图片的地址 |
| | | * @author fengshuonan |
| | | * @since 2.3.0 |
| | | */ |
| | | public static void encode(String content, int width, int height, String srcImagePath, String destImagePath) { |
| | | try { |
| | | ImageIO.write(genBarcode(content, width, height, srcImagePath), "jpg", new File(destImagePath)); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } catch (WriterException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 生成带图片的二维码 |
| | | * |
| | | * @param content 二维码的内容 |
| | | * @param width 宽度 |
| | | * @param height 高度 |
| | | * @param srcImagePath 被镶嵌的图片的地址 |
| | | * @author fengshuonan |
| | | * @since 2.3.0 |
| | | */ |
| | | public static void encode(String content, int width, int height, String srcImagePath, OutputStream outputStream) { |
| | | try { |
| | | ImageIO.write(genBarcode(content, width, height, srcImagePath), "jpg", outputStream); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } catch (WriterException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 创建不带参数的二维码 |
| | | * |
| | | * @author fengshuonan |
| | | * @since 2.3.0 |
| | | */ |
| | | public static void createSimpleQr(String content, int width, int height, String destImagePath) { |
| | | |
| | | FileOutputStream output = null; |
| | | |
| | | try { |
| | | String format = "jpg";// 图像类型 |
| | | Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); |
| | | hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); |
| | | BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵 |
| | | File dest = new File(destImagePath); |
| | | output = new FileOutputStream(dest); |
| | | MatrixToImageWriter.writeToStream(bitMatrix, format, output);// 输出图像 |
| | | } catch (Exception e) { |
| | | log.error("生成二维码出错!ImgQrTool:createSimpleQr()", e); |
| | | } finally { |
| | | try { |
| | | output.close(); |
| | | } catch (IOException e) { |
| | | log.error("生成二维码出错!ImgQrTool:createSimpleQr()", e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static BufferedImage genBarcode(String content, int width, int height, String srcImagePath) |
| | | throws WriterException, IOException { |
| | | // 读取源图像 |
| | | BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH, IMAGE_HEIGHT, true); |
| | | int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; |
| | | for (int i = 0; i < scaleImage.getWidth(); i++) { |
| | | for (int j = 0; j < scaleImage.getHeight(); j++) { |
| | | srcPixels[i][j] = scaleImage.getRGB(i, j); |
| | | } |
| | | } |
| | | |
| | | Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>(); |
| | | hint.put(EncodeHintType.CHARACTER_SET, "utf-8"); |
| | | hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); |
| | | hint.put(EncodeHintType.MARGIN, 1);// 二维码整体白框 |
| | | |
| | | // 生成二维码 |
| | | BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hint); |
| | | |
| | | // 二维矩阵转为一维像素数组 |
| | | int halfW = matrix.getWidth() / 2; |
| | | int halfH = matrix.getHeight() / 2; |
| | | int[] pixels = new int[width * height]; |
| | | |
| | | for (int y = 0; y < matrix.getHeight(); y++) { |
| | | for (int x = 0; x < matrix.getWidth(); x++) { |
| | | // 读取图片 |
| | | if (x > halfW - IMAGE_HALF_WIDTH && x < halfW + IMAGE_HALF_WIDTH && y > halfH - IMAGE_HALF_WIDTH |
| | | && y < halfH + IMAGE_HALF_WIDTH) { |
| | | pixels[y * width + x] = srcPixels[x - halfW + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH]; |
| | | } |
| | | // 在图片四周形成边框 |
| | | else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH |
| | | && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH) |
| | | || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH |
| | | && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH |
| | | && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH) |
| | | || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH |
| | | && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH |
| | | && y < halfH - IMAGE_HALF_WIDTH + FRAME_WIDTH) |
| | | || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH |
| | | && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH |
| | | && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)) { |
| | | pixels[y * width + x] = 0xfffffff; |
| | | } else { |
| | | // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; |
| | | pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 : 0xfffffff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |
| | | image.getRaster().setDataElements(0, 0, width, height, pixels); |
| | | |
| | | return image; |
| | | } |
| | | |
| | | /** |
| | | * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标 |
| | | * |
| | | * @param srcImageFile 源文件地址 |
| | | * @param height 目标高度 |
| | | * @param width 目标宽度 |
| | | * @param hasFiller 比例不对时是否需要补白:true为补白; false为不补白; |
| | | * @throws IOException |
| | | */ |
| | | private static BufferedImage scale(String srcImageFile, int height, int width, boolean hasFiller) |
| | | throws IOException { |
| | | double ratio = 0.0; // 缩放比例 |
| | | File file = new File(srcImageFile); |
| | | BufferedImage srcImage = ImageIO.read(file); |
| | | Image destImage = srcImage.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH); |
| | | // 计算比例 |
| | | if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { |
| | | if (srcImage.getHeight() > srcImage.getWidth()) { |
| | | ratio = (new Integer(height)).doubleValue() / srcImage.getHeight(); |
| | | } else { |
| | | ratio = (new Integer(width)).doubleValue() / srcImage.getWidth(); |
| | | } |
| | | AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null); |
| | | destImage = op.filter(srcImage, null); |
| | | } |
| | | if (hasFiller) {// 补白 |
| | | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |
| | | Graphics2D graphic = image.createGraphics(); |
| | | graphic.setColor(Color.white); |
| | | graphic.fillRect(0, 0, width, height); |
| | | if (width == destImage.getWidth(null)) |
| | | graphic.drawImage(destImage, 0, (height - destImage.getHeight(null)) / 2, destImage.getWidth(null), |
| | | destImage.getHeight(null), Color.white, null); |
| | | else |
| | | graphic.drawImage(destImage, (width - destImage.getWidth(null)) / 2, 0, destImage.getWidth(null), |
| | | destImage.getHeight(null), Color.white, null); |
| | | graphic.dispose(); |
| | | destImage = image; |
| | | } |
| | | return (BufferedImage) destImage; |
| | | } |
| | | |
| | | /** |
| | | * 生成上方带文字的二维码 |
| | | */ |
| | | public static void createQrWithFontsAbove(QrImage para) { |
| | | try { |
| | | // 首先生成二维码图片 |
| | | BufferedImage qrImage = genBarcode(para.getQrContent(), para.getQrWidth(), para.getQrHeight(), para.getQrIconFilePath()); |
| | | |
| | | int qrImageWidth = qrImage.getWidth(); |
| | | int qrImageHeight = qrImage.getHeight(); |
| | | |
| | | String[] splitStrLines = null; |
| | | splitStrLines = splitStrLines(para.getWordContent(), qrImageWidth / para.getWordSize()); |
| | | int fontsImageHeight = splitStrLines.length * para.getWordSize() + 10; //防止文字遮挡 |
| | | |
| | | //创建顶部文字的图片 |
| | | BufferedImage imageWithFonts = new BufferedImage(qrImageWidth, fontsImageHeight, BufferedImage.TYPE_4BYTE_ABGR); |
| | | Graphics fontsImageGraphics = imageWithFonts.getGraphics(); |
| | | fontsImageGraphics.fillRect(0, 0, qrImageWidth, fontsImageHeight); |
| | | fontsImageGraphics.setColor(Color.black); |
| | | fontsImageGraphics.setFont(new Font("宋体", Font.PLAIN, para.getWordSize())); |
| | | |
| | | //文字长度大于一行的长度,进行分行 |
| | | if (para.getWordContent().length() > qrImageWidth / para.getWordSize()) {//每行限制的文字个数 |
| | | for (int i = 0; i < splitStrLines.length; i++) { |
| | | fontsImageGraphics.drawString(splitStrLines[i], 0, para.getWordSize() * (i + 1)); |
| | | } |
| | | } else { |
| | | fontsImageGraphics.drawString( |
| | | para.getWordContent(), |
| | | ((qrImageWidth / para.getWordSize() - para.getWordContent().length()) / 2) * para.getWordSize() + 20, //总长度减去字长度除以2为向右偏移长度 |
| | | para.getWordSize()); |
| | | } |
| | | |
| | | // 从图片中读取RGB |
| | | int[] ImageArrayFonts = new int[qrImageWidth * fontsImageHeight]; |
| | | ImageArrayFonts = imageWithFonts.getRGB(0, 0, qrImageWidth, fontsImageHeight, ImageArrayFonts, 0, qrImageWidth); |
| | | |
| | | int[] ImageArrayQr = new int[qrImageWidth * qrImageHeight]; |
| | | ImageArrayQr = qrImage.getRGB(0, 0, qrImageWidth, qrImageHeight, ImageArrayQr, 0, qrImageWidth); |
| | | |
| | | // 生成新图片 |
| | | BufferedImage ImageNew = new BufferedImage(qrImageWidth, qrImageHeight + fontsImageHeight, BufferedImage.TYPE_INT_RGB); |
| | | ImageNew.setRGB(0, 0, qrImageWidth, fontsImageHeight, ImageArrayFonts, 0, qrImageWidth);// 设置上半部分的RGB |
| | | ImageNew.setRGB(0, fontsImageHeight, qrImageWidth, qrImageHeight, ImageArrayQr, 0, qrImageWidth);// 设置下半部分的RGB |
| | | |
| | | File outFile = new File(para.getFileOutputPath()); |
| | | ImageIO.write(ImageNew, "jpg", outFile); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 一行字符串拆分成多行 |
| | | */ |
| | | private static String[] splitStrLines(String str, int len) { |
| | | int blocks = str.length() / len + 1; |
| | | String[] strs = new String[blocks]; |
| | | for (int i = 0; i < blocks; i++) { |
| | | if ((i + 1) * len > str.length()) { |
| | | strs[i] = str.substring(i * len); |
| | | } else { |
| | | strs[i] = str.substring(i * len, (i + 1) * len); |
| | | } |
| | | } |
| | | return strs; |
| | | } |
| | | |
| | | public static void main(String[] args) throws IOException { |
| | | for (int i = 1; i <= 1; i++) { |
| | | QrImage para = new QrImage.Builder() |
| | | .setFileOutputPath("D:\\二维码\\test\\" + i + ".jpg") |
| | | .setQrContent("http://www.baidu.com?a=" + "123") |
| | | .setQrHeight(300) |
| | | .setQrWidth(300) |
| | | .setQrIconFilePath("D:\\二维码\\中间图标\\1.png") |
| | | .setTopWrodHeight(100) |
| | | .setWordContent("test" + 1) |
| | | .setWordSize(18).build(); |
| | | ImgQrTool.createQrWithFontsAbove(para); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2012 ZXing authors |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | |
| | | package com.stylefeng.guns.core.qr; |
| | | |
| | | import java.awt.image.BufferedImage; |
| | | |
| | | /** |
| | | * Encapsulates custom configuration used in methods of {@link MatrixToImageWriter}. |
| | | */ |
| | | public final class MatrixToImageConfig { |
| | | |
| | | public static final int BLACK = 0xFF000000; |
| | | public static final int WHITE = 0xFFFFFFFF; |
| | | |
| | | private final int onColor; |
| | | private final int offColor; |
| | | |
| | | /** |
| | | * Creates a default config with on color {@link #BLACK} and off color {@link #WHITE}, generating normal |
| | | * black-on-white barcodes. |
| | | */ |
| | | public MatrixToImageConfig() { |
| | | this(BLACK, WHITE); |
| | | } |
| | | |
| | | /** |
| | | * @param onColor pixel on color, specified as an ARGB value as an int |
| | | * @param offColor pixel off color, specified as an ARGB value as an int |
| | | */ |
| | | public MatrixToImageConfig(int onColor, int offColor) { |
| | | this.onColor = onColor; |
| | | this.offColor = offColor; |
| | | } |
| | | |
| | | public int getPixelOnColor() { |
| | | return onColor; |
| | | } |
| | | |
| | | public int getPixelOffColor() { |
| | | return offColor; |
| | | } |
| | | |
| | | int getBufferedImageColorModel() { |
| | | // Use faster BINARY if colors match default |
| | | return onColor == BLACK && offColor == WHITE ? BufferedImage.TYPE_BYTE_BINARY : BufferedImage.TYPE_INT_RGB; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2009 ZXing authors |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.qr; |
| | | |
| | | import com.google.zxing.common.BitMatrix; |
| | | |
| | | import javax.imageio.ImageIO; |
| | | import java.awt.image.BufferedImage; |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.OutputStream; |
| | | import java.nio.file.Path; |
| | | |
| | | /** |
| | | * Writes a {@link BitMatrix} to {@link BufferedImage}, |
| | | * file or stream. Provided here instead of core since it depends on |
| | | * Java SE libraries. |
| | | * |
| | | * @author Sean Owen |
| | | */ |
| | | public final class MatrixToImageWriter { |
| | | |
| | | private static final MatrixToImageConfig DEFAULT_CONFIG = new MatrixToImageConfig(); |
| | | |
| | | private MatrixToImageWriter() {} |
| | | |
| | | /** |
| | | * Renders a {@link BitMatrix} as an image, where "false" bits are rendered |
| | | * as white, and "true" bits are rendered as black. |
| | | */ |
| | | public static BufferedImage toBufferedImage(BitMatrix matrix) { |
| | | return toBufferedImage(matrix, DEFAULT_CONFIG); |
| | | } |
| | | |
| | | /** |
| | | * As {@link #toBufferedImage(BitMatrix)}, but allows customization of the output. |
| | | */ |
| | | public static BufferedImage toBufferedImage(BitMatrix matrix, MatrixToImageConfig config) { |
| | | int width = matrix.getWidth(); |
| | | int height = matrix.getHeight(); |
| | | BufferedImage image = new BufferedImage(width, height, config.getBufferedImageColorModel()); |
| | | int onColor = config.getPixelOnColor(); |
| | | int offColor = config.getPixelOffColor(); |
| | | for (int x = 0; x < width; x++) { |
| | | for (int y = 0; y < height; y++) { |
| | | image.setRGB(x, y, matrix.get(x, y) ? onColor : offColor); |
| | | } |
| | | } |
| | | return image; |
| | | } |
| | | |
| | | /** |
| | | * @deprecated use {@link #writeToPath(BitMatrix, String, Path)} |
| | | */ |
| | | @Deprecated |
| | | public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException { |
| | | writeToPath(matrix, format, file.toPath()); |
| | | } |
| | | |
| | | /** |
| | | * Writes a {@link BitMatrix} to a file. |
| | | * |
| | | * @see #toBufferedImage(BitMatrix) |
| | | */ |
| | | public static void writeToPath(BitMatrix matrix, String format, Path file) throws IOException { |
| | | writeToPath(matrix, format, file, DEFAULT_CONFIG); |
| | | } |
| | | |
| | | /** |
| | | * @deprecated use {@link #writeToPath(BitMatrix, String, Path, MatrixToImageConfig)} |
| | | */ |
| | | @Deprecated |
| | | public static void writeToFile(BitMatrix matrix, String format, File file, MatrixToImageConfig config) |
| | | throws IOException { |
| | | writeToPath(matrix, format, file.toPath(), config); |
| | | } |
| | | |
| | | /** |
| | | * As {@link #writeToFile(BitMatrix, String, File)}, but allows customization of the output. |
| | | */ |
| | | public static void writeToPath(BitMatrix matrix, String format, Path file, MatrixToImageConfig config) |
| | | throws IOException { |
| | | BufferedImage image = toBufferedImage(matrix, config); |
| | | if (!ImageIO.write(image, format, file.toFile())) { |
| | | throw new IOException("Could not write an image of format " + format + " to " + file); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Writes a {@link BitMatrix} to a stream. |
| | | * |
| | | * @see #toBufferedImage(BitMatrix) |
| | | */ |
| | | public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException { |
| | | writeToStream(matrix, format, stream, DEFAULT_CONFIG); |
| | | } |
| | | |
| | | /** |
| | | * As {@link #writeToStream(BitMatrix, String, OutputStream)}, but allows customization of the output. |
| | | */ |
| | | public static void writeToStream(BitMatrix matrix, String format, OutputStream stream, MatrixToImageConfig config) |
| | | throws IOException { |
| | | BufferedImage image = toBufferedImage(matrix, config); |
| | | if (!ImageIO.write(image, format, stream)) { |
| | | throw new IOException("Could not write an image of format " + format); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.qr; |
| | | |
| | | /** |
| | | * 二维码图片对象 |
| | | * |
| | | * @author fengshuonan |
| | | * @date 2016年12月8日 上午11:37:09 |
| | | */ |
| | | public class QrImage { |
| | | |
| | | /** |
| | | * 二维码的内容 |
| | | */ |
| | | private String qrContent; |
| | | |
| | | /** |
| | | * 二维码的宽度 |
| | | */ |
| | | private int qrWidth; |
| | | |
| | | /** |
| | | * 二维码的高度 |
| | | */ |
| | | private int qrHeight; |
| | | |
| | | /** |
| | | * 二维码中间图标的文件路径 |
| | | */ |
| | | private String qrIconFilePath; |
| | | |
| | | /** |
| | | * 二维码中间小图标的边长 |
| | | */ |
| | | private int qrIconWidth; |
| | | |
| | | /** |
| | | * 顶部文字的高度 |
| | | */ |
| | | private int topWrodHeight; |
| | | |
| | | /** |
| | | * 文字的大小 |
| | | */ |
| | | private int wordSize; |
| | | |
| | | /** |
| | | * 文字的内容 |
| | | */ |
| | | private String wordContent; |
| | | |
| | | /** |
| | | * 文件的输出路径 |
| | | */ |
| | | private String fileOutputPath; |
| | | |
| | | public static class Builder { |
| | | private String qrContent; |
| | | private int qrWidth; |
| | | private int qrHeight; |
| | | private String qrIconFilePath; |
| | | private int topWrodHeight; |
| | | private int wordSize; |
| | | private String wordContent; |
| | | private String fileOutputPath; |
| | | private int qrIconWidth; |
| | | |
| | | public Builder() { |
| | | } |
| | | |
| | | public Builder setQrContent(String qrContent) { |
| | | this.qrContent = qrContent; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setQrWidth(int qrWidth) { |
| | | this.qrWidth = qrWidth; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setQrHeight(int qrHeight) { |
| | | this.qrHeight = qrHeight; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setQrIconFilePath(String qrIconFilePath) { |
| | | this.qrIconFilePath = qrIconFilePath; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTopWrodHeight(int topWrodHeight) { |
| | | this.topWrodHeight = topWrodHeight; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setWordSize(int wordSize) { |
| | | this.wordSize = wordSize; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setWordContent(String wordContent) { |
| | | this.wordContent = wordContent; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setFileOutputPath(String fileOutputPath) { |
| | | this.fileOutputPath = fileOutputPath; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setQrIconWidth(int qrIconWidth) { |
| | | this.qrIconWidth = qrIconWidth; |
| | | return this; |
| | | } |
| | | |
| | | public QrImage build() { |
| | | return new QrImage(this.qrContent, this.qrWidth, this.qrHeight, this.qrIconFilePath, this.qrIconWidth, |
| | | this.topWrodHeight, this.wordSize, this.wordContent, this.fileOutputPath); |
| | | } |
| | | } |
| | | |
| | | public QrImage(String qrContent, int qrWidth, int qrHeight, String qrIconFilePath, int qrIconWidth, |
| | | int topWrodHeight, int wordSize, String wordContent, String fileOutputPath) { |
| | | super(); |
| | | this.qrContent = qrContent; |
| | | this.qrWidth = qrWidth; |
| | | this.qrHeight = qrHeight; |
| | | this.qrIconFilePath = qrIconFilePath; |
| | | this.qrIconWidth = qrIconWidth; |
| | | this.topWrodHeight = topWrodHeight; |
| | | this.wordSize = wordSize; |
| | | this.wordContent = wordContent; |
| | | this.fileOutputPath = fileOutputPath; |
| | | } |
| | | |
| | | public String getQrContent() { |
| | | return qrContent; |
| | | } |
| | | |
| | | public int getQrWidth() { |
| | | return qrWidth; |
| | | } |
| | | |
| | | public int getQrHeight() { |
| | | return qrHeight; |
| | | } |
| | | |
| | | public String getQrIconFilePath() { |
| | | return qrIconFilePath; |
| | | } |
| | | |
| | | public int getTopWrodHeight() { |
| | | return topWrodHeight; |
| | | } |
| | | |
| | | public int getWordSize() { |
| | | return wordSize; |
| | | } |
| | | |
| | | public String getWordContent() { |
| | | return wordContent; |
| | | } |
| | | |
| | | public String getFileOutputPath() { |
| | | return fileOutputPath; |
| | | } |
| | | |
| | | public int getQrIconWidth() { |
| | | return qrIconWidth; |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 基本变量类型的枚举 |
| | | * |
| | | * @author xiaoleilu |
| | | */ |
| | | public enum BasicType { |
| | | BYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING; |
| | | |
| | | /** |
| | | * 原始类型为Key,包装类型为Value,例如: int.class -> Integer.class. |
| | | */ |
| | | public static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<Class<?>, Class<?>>(8); |
| | | |
| | | /** |
| | | * 包装类型为Key,原始类型为Value,例如: Integer.class -> int.class. |
| | | */ |
| | | public static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>(8); |
| | | |
| | | static { |
| | | wrapperPrimitiveMap.put(Boolean.class, boolean.class); |
| | | wrapperPrimitiveMap.put(Byte.class, byte.class); |
| | | wrapperPrimitiveMap.put(Character.class, char.class); |
| | | wrapperPrimitiveMap.put(Double.class, double.class); |
| | | wrapperPrimitiveMap.put(Float.class, float.class); |
| | | wrapperPrimitiveMap.put(Integer.class, int.class); |
| | | wrapperPrimitiveMap.put(Long.class, long.class); |
| | | wrapperPrimitiveMap.put(Short.class, short.class); |
| | | |
| | | for (Map.Entry<Class<?>, Class<?>> entry : wrapperPrimitiveMap.entrySet()) { |
| | | primitiveWrapperMap.put(entry.getValue(), entry.getKey()); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | import com.stylefeng.guns.core.util.Convert; |
| | | |
| | | import java.beans.*; |
| | | import java.lang.reflect.Method; |
| | | import java.util.*; |
| | | import java.util.Map.Entry; |
| | | |
| | | /** |
| | | * Bean工具类 |
| | | * |
| | | * @author Looly |
| | | */ |
| | | public class BeanKit { |
| | | |
| | | /** |
| | | * 判断是否为Bean对象 |
| | | * |
| | | * @param clazz 待测试类 |
| | | * @return 是否为Bean对象 |
| | | */ |
| | | public static boolean isBean(Class<?> clazz) { |
| | | if (ClassKit.isNormalClass(clazz)) { |
| | | Method[] methods = clazz.getMethods(); |
| | | for (Method method : methods) { |
| | | if (method.getParameterTypes().length == 1 && method.getName().startsWith("set")) { |
| | | //检测包含标准的setXXX方法即视为标准的JavaBean |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | public static PropertyEditor findEditor(Class<?> type) { |
| | | return PropertyEditorManager.findEditor(type); |
| | | } |
| | | |
| | | /** |
| | | * 获得Bean字段描述数组 |
| | | * |
| | | * @param clazz Bean类 |
| | | * @return 字段描述数组 |
| | | * @throws IntrospectionException |
| | | */ |
| | | public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws IntrospectionException { |
| | | return Introspector.getBeanInfo(clazz).getPropertyDescriptors(); |
| | | } |
| | | |
| | | /** |
| | | * 获得字段名和字段描述Map |
| | | * |
| | | * @param clazz Bean类 |
| | | * @return 字段名和字段描述Map |
| | | * @throws IntrospectionException |
| | | */ |
| | | public static Map<String, PropertyDescriptor> getFieldNamePropertyDescriptorMap(Class<?> clazz) throws IntrospectionException { |
| | | final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz); |
| | | Map<String, PropertyDescriptor> map = new HashMap<>(); |
| | | for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { |
| | | map.put(propertyDescriptor.getName(), propertyDescriptor); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 获得Bean类属性描述 |
| | | * |
| | | * @param clazz Bean类 |
| | | * @param fieldName 字段名 |
| | | * @return PropertyDescriptor |
| | | * @throws IntrospectionException |
| | | */ |
| | | public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, final String fieldName) throws IntrospectionException { |
| | | PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz); |
| | | for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { |
| | | if (ObjectKit.equals(fieldName, propertyDescriptor.getName())) { |
| | | return propertyDescriptor; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Map转换为Bean对象 |
| | | * |
| | | * @param map Map |
| | | * @param beanClass Bean Class |
| | | * @return Bean |
| | | */ |
| | | public static <T> T mapToBean(Map<?, ?> map, Class<T> beanClass) { |
| | | return fillBeanWithMap(map, ClassKit.newInstance(beanClass)); |
| | | } |
| | | |
| | | /** |
| | | * Map转换为Bean对象<br> |
| | | * 忽略大小写 |
| | | * |
| | | * @param map Map |
| | | * @param beanClass Bean Class |
| | | * @return Bean |
| | | */ |
| | | public static <T> T mapToBeanIgnoreCase(Map<?, ?> map, Class<T> beanClass) { |
| | | return fillBeanWithMapIgnoreCase(map, ClassKit.newInstance(beanClass)); |
| | | } |
| | | |
| | | /** |
| | | * 使用Map填充Bean对象 |
| | | * |
| | | * @param map Map |
| | | * @param bean Bean |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBeanWithMap(final Map<?, ?> map, T bean) { |
| | | return fillBean(bean, new ValueProvider() { |
| | | @Override |
| | | public Object value(String name) { |
| | | return map.get(name); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 使用Map填充Bean对象,可配置将下划线转换为驼峰 |
| | | * |
| | | * @param map Map |
| | | * @param bean Bean |
| | | * @param isToCamelCase 是否将下划线模式转换为驼峰模式 |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBeanWithMap(Map<?, ?> map, T bean, boolean isToCamelCase) { |
| | | if (isToCamelCase) { |
| | | final Map<Object, Object> map2 = new HashMap<Object, Object>(); |
| | | for (Entry<?, ?> entry : map.entrySet()) { |
| | | final Object key = entry.getKey(); |
| | | if (null != key && key instanceof String) { |
| | | final String keyStr = (String) key; |
| | | map2.put(StrKit.toCamelCase(keyStr), entry.getValue()); |
| | | } else { |
| | | map2.put(key, entry.getValue()); |
| | | } |
| | | } |
| | | return fillBeanWithMap(map2, bean); |
| | | } |
| | | |
| | | return fillBeanWithMap(map, bean); |
| | | } |
| | | |
| | | /** |
| | | * 使用Map填充Bean对象,忽略大小写 |
| | | * |
| | | * @param map Map |
| | | * @param bean Bean |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBeanWithMapIgnoreCase(Map<?, ?> map, T bean) { |
| | | final Map<Object, Object> map2 = new HashMap<Object, Object>(); |
| | | for (Entry<?, ?> entry : map.entrySet()) { |
| | | final Object key = entry.getKey(); |
| | | if (key instanceof String) { |
| | | final String keyStr = (String) key; |
| | | map2.put(keyStr.toLowerCase(), entry.getValue()); |
| | | } else { |
| | | map2.put(key, entry.getValue()); |
| | | } |
| | | } |
| | | |
| | | return fillBean(bean, new ValueProvider() { |
| | | @Override |
| | | public Object value(String name) { |
| | | return map2.get(name.toLowerCase()); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * ServletRequest 参数转Bean |
| | | * |
| | | * @param request ServletRequest |
| | | * @param beanClass Bean Class |
| | | * @return Bean |
| | | */ |
| | | public static <T> T requestParamToBean(javax.servlet.ServletRequest request, Class<T> beanClass) { |
| | | return fillBeanWithRequestParam(request, ClassKit.newInstance(beanClass)); |
| | | } |
| | | |
| | | /** |
| | | * ServletRequest 参数转Bean |
| | | * |
| | | * @param request ServletRequest |
| | | * @param bean Bean |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBeanWithRequestParam(final javax.servlet.ServletRequest request, T bean) { |
| | | final String beanName = StrKit.lowerFirst(bean.getClass().getSimpleName()); |
| | | return fillBean(bean, new ValueProvider() { |
| | | @Override |
| | | public Object value(String name) { |
| | | String value = request.getParameter(name); |
| | | if (StrKit.isEmpty(value)) { |
| | | // 使用类名前缀尝试查找值 |
| | | value = request.getParameter(beanName + StrKit.DOT + name); |
| | | if (StrKit.isEmpty(value)) { |
| | | // 此处取得的值为空时跳过,包括null和"" |
| | | value = null; |
| | | } |
| | | } |
| | | return value; |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * ServletRequest 参数转Bean |
| | | * |
| | | * @param <T> |
| | | * @param beanClass Bean Class |
| | | * @param valueProvider 值提供者 |
| | | * @return Bean |
| | | */ |
| | | public static <T> T toBean(Class<T> beanClass, ValueProvider valueProvider) { |
| | | return fillBean(ClassKit.newInstance(beanClass), valueProvider); |
| | | } |
| | | |
| | | /** |
| | | * 填充Bean |
| | | * |
| | | * @param <T> |
| | | * @param bean Bean |
| | | * @param valueProvider 值提供者 |
| | | * @return Bean |
| | | */ |
| | | public static <T> T fillBean(T bean, ValueProvider valueProvider) { |
| | | if (null == valueProvider) { |
| | | return bean; |
| | | } |
| | | |
| | | Class<?> beanClass = bean.getClass(); |
| | | try { |
| | | PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(beanClass); |
| | | String propertyName; |
| | | Object value; |
| | | for (PropertyDescriptor property : propertyDescriptors) { |
| | | propertyName = property.getName(); |
| | | value = valueProvider.value(propertyName); |
| | | if (null == value) { |
| | | continue; |
| | | } |
| | | try { |
| | | property.getWriteMethod().invoke(bean, Convert.parse(property.getPropertyType(), value)); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(e); |
| | | } |
| | | return bean; |
| | | } |
| | | |
| | | /** |
| | | * 对象转Map |
| | | * |
| | | * @param bean bean对象 |
| | | * @return Map |
| | | */ |
| | | public static <T> Map<String, Object> beanToMap(T bean) { |
| | | return beanToMap(bean, false); |
| | | } |
| | | |
| | | /** |
| | | * 对象转Map |
| | | * |
| | | * @param bean bean对象 |
| | | * @return Map |
| | | */ |
| | | public static <T> List<Map<String, Object>> listToMapList(List<T> bean) { |
| | | ArrayList<Map<String, Object>> maps = new ArrayList<>(); |
| | | for (T t : bean) { |
| | | maps.add(beanToMap(bean, false)); |
| | | } |
| | | return maps; |
| | | } |
| | | |
| | | /** |
| | | * 对象转Map |
| | | * |
| | | * @param bean bean对象 |
| | | * @param isToUnderlineCase 是否转换为下划线模式 |
| | | * @return Map |
| | | */ |
| | | public static <T> Map<String, Object> beanToMap(T bean, boolean isToUnderlineCase) { |
| | | |
| | | if (bean == null) { |
| | | return null; |
| | | } |
| | | Map<String, Object> map = new HashMap<String, Object>(); |
| | | try { |
| | | final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(bean.getClass()); |
| | | for (PropertyDescriptor property : propertyDescriptors) { |
| | | String key = property.getName(); |
| | | // 过滤class属性 |
| | | if (false == key.equals("class")) { |
| | | // 得到property对应的getter方法 |
| | | Method getter = property.getReadMethod(); |
| | | Object value = getter.invoke(bean); |
| | | if (null != value) { |
| | | map.put(isToUnderlineCase ? StrKit.toUnderlineCase(key) : key, value); |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(e); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 复制Bean对象属性 |
| | | * |
| | | * @param source 源Bean对象 |
| | | * @param target 目标Bean对象 |
| | | */ |
| | | public static void copyProperties(Object source, Object target) { |
| | | copyProperties(source, target, CopyOptions.create()); |
| | | } |
| | | |
| | | /** |
| | | * 复制Bean对象属性<br> |
| | | * 限制类用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 |
| | | * |
| | | * @param source 源Bean对象 |
| | | * @param target 目标Bean对象 |
| | | * @param ignoreProperties 不拷贝的的属性列表 |
| | | */ |
| | | public static void copyProperties(Object source, Object target, String... ignoreProperties) { |
| | | copyProperties(source, target, CopyOptions.create().setIgnoreProperties(ignoreProperties)); |
| | | } |
| | | |
| | | /** |
| | | * 复制Bean对象属性<br> |
| | | * 限制类用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 |
| | | * |
| | | * @param source 源Bean对象 |
| | | * @param target 目标Bean对象 |
| | | * @param copyOptions 拷贝选项,见 {@link CopyOptions} |
| | | */ |
| | | public static void copyProperties(Object source, Object target, CopyOptions copyOptions) { |
| | | if (null == copyOptions) { |
| | | copyOptions = new CopyOptions(); |
| | | } |
| | | |
| | | Class<?> actualEditable = target.getClass(); |
| | | if (copyOptions.editable != null) { |
| | | //检查限制类是否为target的父类或接口 |
| | | if (!copyOptions.editable.isInstance(target)) { |
| | | throw new IllegalArgumentException(StrKit.format("Target class [{}] not assignable to Editable class [{}]", target.getClass().getName(), copyOptions.editable.getName())); |
| | | } |
| | | actualEditable = copyOptions.editable; |
| | | } |
| | | PropertyDescriptor[] targetPds = null; |
| | | Map<String, PropertyDescriptor> sourcePdMap; |
| | | try { |
| | | sourcePdMap = getFieldNamePropertyDescriptorMap(source.getClass()); |
| | | targetPds = getPropertyDescriptors(actualEditable); |
| | | } catch (IntrospectionException e) { |
| | | throw new ToolBoxException(e); |
| | | } |
| | | |
| | | HashSet<String> ignoreSet = copyOptions.ignoreProperties != null ? CollectionKit.newHashSet(copyOptions.ignoreProperties) : null; |
| | | for (PropertyDescriptor targetPd : targetPds) { |
| | | Method writeMethod = targetPd.getWriteMethod(); |
| | | if (writeMethod != null && (ignoreSet == null || false == ignoreSet.contains(targetPd.getName()))) { |
| | | PropertyDescriptor sourcePd = sourcePdMap.get(targetPd.getName()); |
| | | if (sourcePd != null) { |
| | | Method readMethod = sourcePd.getReadMethod(); |
| | | // 源对象字段的getter方法返回值必须可转换为目标对象setter方法的第一个参数 |
| | | if (readMethod != null && ClassKit.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { |
| | | try { |
| | | Object value = ClassKit.setAccessible(readMethod).invoke(source); |
| | | if (null != value || false == copyOptions.isIgnoreNullValue) { |
| | | ClassKit.setAccessible(writeMethod).invoke(target, value); |
| | | } |
| | | } catch (Throwable ex) { |
| | | throw new ToolBoxException(ex, "Copy property [{}] to [{}] error: {}", sourcePd.getName(), targetPd.getName(), ex.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 值提供者,用于提供Bean注入时参数对应值得抽象接口<br> |
| | | * 继承或匿名实例化此接口<br> |
| | | * 在Bean注入过程中,Bean获得字段名,通过外部方式根据这个字段名查找相应的字段值,然后注入Bean<br> |
| | | * |
| | | * @author Looly |
| | | */ |
| | | public static interface ValueProvider { |
| | | /** |
| | | * 获取值 |
| | | * |
| | | * @param name Bean对象中参数名 |
| | | * @return 对应参数名的值 |
| | | */ |
| | | public Object value(String name); |
| | | } |
| | | |
| | | /** |
| | | * 属性拷贝选项<br> |
| | | * 包括:<br> |
| | | * 1、限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类<br> |
| | | * 2、是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null<br> |
| | | * 3、忽略的属性列表,设置一个属性列表,不拷贝这些属性值<br> |
| | | * |
| | | * @author Looly |
| | | */ |
| | | public static class CopyOptions { |
| | | /** |
| | | * 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 |
| | | */ |
| | | private Class<?> editable; |
| | | /** |
| | | * 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | */ |
| | | private boolean isIgnoreNullValue; |
| | | /** |
| | | * 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | */ |
| | | private String[] ignoreProperties; |
| | | |
| | | /** |
| | | * 创建拷贝选项 |
| | | * |
| | | * @return 拷贝选项 |
| | | */ |
| | | public static CopyOptions create() { |
| | | return new CopyOptions(); |
| | | } |
| | | |
| | | /** |
| | | * 创建拷贝选项 |
| | | * |
| | | * @param editable 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性 |
| | | * @param isIgnoreNullValue 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | * @param ignoreProperties 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | * @return 拷贝选项 |
| | | */ |
| | | public static CopyOptions create(Class<?> editable, boolean isIgnoreNullValue, String... ignoreProperties) { |
| | | return new CopyOptions(editable, isIgnoreNullValue, ignoreProperties); |
| | | } |
| | | |
| | | /** |
| | | * 构造拷贝选项 |
| | | */ |
| | | public CopyOptions() { |
| | | } |
| | | |
| | | /** |
| | | * 构造拷贝选项 |
| | | * |
| | | * @param editable 限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性 |
| | | * @param isIgnoreNullValue 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | * @param ignoreProperties 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | */ |
| | | public CopyOptions(Class<?> editable, boolean isIgnoreNullValue, String... ignoreProperties) { |
| | | this.editable = editable; |
| | | this.isIgnoreNullValue = isIgnoreNullValue; |
| | | this.ignoreProperties = ignoreProperties; |
| | | } |
| | | |
| | | /** |
| | | * 设置限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性 |
| | | * |
| | | * @param editable 限制的类或接口 |
| | | * @return CopyOptions |
| | | */ |
| | | public CopyOptions setEditable(Class<?> editable) { |
| | | this.editable = editable; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | * |
| | | * @param isIgnoreNullVall 是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null |
| | | * @return CopyOptions |
| | | */ |
| | | public CopyOptions setIgnoreNullValue(boolean isIgnoreNullVall) { |
| | | this.isIgnoreNullValue = isIgnoreNullVall; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | * |
| | | * @param ignoreProperties 忽略的属性列表,设置一个属性列表,不拷贝这些属性值 |
| | | * @return CopyOptions |
| | | */ |
| | | public CopyOptions setIgnoreProperties(String... ignoreProperties) { |
| | | this.ignoreProperties = ignoreProperties; |
| | | return this; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | |
| | | import java.lang.reflect.Method; |
| | | import java.lang.reflect.Modifier; |
| | | |
| | | /** |
| | | * 类工具类 |
| | | * 1、扫描指定包下的所有类<br> |
| | | * 参考 http://www.oschina.net/code/snippet_234657_22722 |
| | | * @author seaside_hi, xiaoleilu, chill |
| | | * |
| | | */ |
| | | public class ClassKit { |
| | | |
| | | private ClassKit() { |
| | | // 静态类不可实例化 |
| | | } |
| | | |
| | | /** |
| | | * 是否为标准的类<br> |
| | | * 这个类必须:<br> |
| | | * 1、非接口 2、非抽象类 3、非Enum枚举 4、非数组 5、非注解 6、非原始类型(int, long等) |
| | | * |
| | | * @param clazz 类 |
| | | * @return 是否为标准类 |
| | | */ |
| | | public static boolean isNormalClass(Class<?> clazz) { |
| | | return null != clazz && false == clazz.isInterface() && false == isAbstract(clazz) && false == clazz.isEnum() && false == clazz.isArray() && false == clazz.isAnnotation() && false == clazz |
| | | .isSynthetic() && false == clazz.isPrimitive(); |
| | | } |
| | | |
| | | /** |
| | | * 是否为抽象类 |
| | | * |
| | | * @param clazz 类 |
| | | * @return 是否为抽象类 |
| | | */ |
| | | public static boolean isAbstract(Class<?> clazz) { |
| | | return Modifier.isAbstract(clazz.getModifiers()); |
| | | } |
| | | |
| | | /** |
| | | * 实例化对象 |
| | | * |
| | | * @param clazz 类名 |
| | | * @return 对象 |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static <T> T newInstance(String clazz) { |
| | | if (null == clazz) |
| | | return null; |
| | | try { |
| | | return (T) Class.forName(clazz).newInstance(); |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Instance class [{}] error!", clazz), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 实例化对象 |
| | | * |
| | | * @param clazz 类 |
| | | * @return 对象 |
| | | */ |
| | | public static <T> T newInstance(Class<T> clazz) { |
| | | if (null == clazz) |
| | | return null; |
| | | try { |
| | | return (T) clazz.newInstance(); |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Instance class [{}] error!", clazz), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 实例化对象 |
| | | * |
| | | * @param clazz 类 |
| | | * @return 对象 |
| | | */ |
| | | public static <T> T newInstance(Class<T> clazz, Object... params) { |
| | | if (null == clazz) |
| | | return null; |
| | | if (CollectionKit.isEmpty(params)) { |
| | | return newInstance(clazz); |
| | | } |
| | | try { |
| | | return clazz.getDeclaredConstructor(getClasses(params)).newInstance(params); |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Instance class [{}] error!", clazz), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获得对象数组的类数组 |
| | | * @param objects 对象数组 |
| | | * @return 类数组 |
| | | */ |
| | | public static Class<?>[] getClasses(Object... objects){ |
| | | Class<?>[] classes = new Class<?>[objects.length]; |
| | | for (int i = 0; i < objects.length; i++) { |
| | | classes[i] = objects[i].getClass(); |
| | | } |
| | | return classes; |
| | | } |
| | | |
| | | /** |
| | | * 检查目标类是否可以从原类转化<br> |
| | | * 转化包括:<br> |
| | | * 1、原类是对象,目标类型是原类型实现的接口<br> |
| | | * 2、目标类型是原类型的父类<br> |
| | | * 3、两者是原始类型或者包装类型(相互转换) |
| | | * |
| | | * @param targetType 目标类型 |
| | | * @param sourceType 原类型 |
| | | * @return 是否可转化 |
| | | */ |
| | | public static boolean isAssignable(Class<?> targetType, Class<?> sourceType) { |
| | | if (null == targetType || null == sourceType) { |
| | | return false; |
| | | } |
| | | |
| | | // 对象类型 |
| | | if (targetType.isAssignableFrom(sourceType)) { |
| | | return true; |
| | | } |
| | | |
| | | // 基本类型 |
| | | if (targetType.isPrimitive()) { |
| | | // 原始类型 |
| | | Class<?> resolvedPrimitive = BasicType.wrapperPrimitiveMap.get(sourceType); |
| | | if (resolvedPrimitive != null && targetType.equals(resolvedPrimitive)) { |
| | | return true; |
| | | } |
| | | } else { |
| | | // 包装类型 |
| | | Class<?> resolvedWrapper = BasicType.primitiveWrapperMap.get(sourceType); |
| | | if (resolvedWrapper != null && targetType.isAssignableFrom(resolvedWrapper)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 设置方法为可访问 |
| | | * |
| | | * @param method 方法 |
| | | * @return 方法 |
| | | */ |
| | | public static Method setAccessible(Method method) { |
| | | if (null != method && ClassKit.isNotPublic(method)) { |
| | | method.setAccessible(true); |
| | | } |
| | | return method; |
| | | } |
| | | |
| | | /** |
| | | * 指定类是否为非public |
| | | * |
| | | * @param clazz 类 |
| | | * @return 是否为非public |
| | | */ |
| | | public static boolean isNotPublic(Class<?> clazz) { |
| | | return false == isPublic(clazz); |
| | | } |
| | | |
| | | /** |
| | | * 指定方法是否为非public |
| | | * |
| | | * @param method 方法 |
| | | * @return 是否为非public |
| | | */ |
| | | public static boolean isNotPublic(Method method) { |
| | | return false == isPublic(method); |
| | | } |
| | | |
| | | /** |
| | | * 指定类是否为Public |
| | | * |
| | | * @param clazz 类 |
| | | * @return 是否为public |
| | | */ |
| | | public static boolean isPublic(Class<?> clazz) { |
| | | if (null == clazz) { |
| | | throw new NullPointerException("Class to provided is null."); |
| | | } |
| | | return Modifier.isPublic(clazz.getModifiers()); |
| | | } |
| | | |
| | | /** |
| | | * 指定方法是否为Public |
| | | * |
| | | * @param method 方法 |
| | | * @return 是否为public |
| | | */ |
| | | public static boolean isPublic(Method method) { |
| | | if (null == method) { |
| | | throw new NullPointerException("Method to provided is null."); |
| | | } |
| | | return isPublic(method.getDeclaringClass()); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | |
| | | import java.lang.reflect.Array; |
| | | import java.util.*; |
| | | import java.util.Map.Entry; |
| | | |
| | | /** |
| | | * 集合相关工具类,包括数组 |
| | | * |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class CollectionKit { |
| | | |
| | | private CollectionKit() { |
| | | // 静态类不可实例化 |
| | | } |
| | | |
| | | /** |
| | | * 以 conjunction 为分隔符将集合转换为字符串 |
| | | * |
| | | * @param <T> 被处理的集合 |
| | | * @param collection 集合 |
| | | * @param conjunction 分隔符 |
| | | * @return 连接后的字符串 |
| | | */ |
| | | public static <T> String join(Iterable<T> collection, String conjunction) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | boolean isFirst = true; |
| | | for (T item : collection) { |
| | | if (isFirst) { |
| | | isFirst = false; |
| | | } else { |
| | | sb.append(conjunction); |
| | | } |
| | | sb.append(item); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 以 conjunction 为分隔符将数组转换为字符串 |
| | | * |
| | | * @param <T> 被处理的集合 |
| | | * @param array 数组 |
| | | * @param conjunction 分隔符 |
| | | * @return 连接后的字符串 |
| | | */ |
| | | public static <T> String join(T[] array, String conjunction) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | boolean isFirst = true; |
| | | for (T item : array) { |
| | | if (isFirst) { |
| | | isFirst = false; |
| | | } else { |
| | | sb.append(conjunction); |
| | | } |
| | | sb.append(item); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 将多个集合排序并显示不同的段落(分页) |
| | | * @param pageNo 页码 |
| | | * @param numPerPage 每页的条目数 |
| | | * @param comparator 比较器 |
| | | * @param colls 集合数组 |
| | | * @return 分页后的段落内容 |
| | | */ |
| | | @SafeVarargs |
| | | public static <T> List<T> sortPageAll(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) { |
| | | final List<T> result = new ArrayList<T>(); |
| | | for (Collection<T> coll : colls) { |
| | | result.addAll(coll); |
| | | } |
| | | |
| | | Collections.sort(result, comparator); |
| | | |
| | | //第一页且数目少于第一页显示的数目 |
| | | if(pageNo <=1 && result.size() <= numPerPage) { |
| | | return result; |
| | | } |
| | | |
| | | final int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage); |
| | | return result.subList(startEnd[0], startEnd[1]); |
| | | } |
| | | |
| | | /** |
| | | * 将多个集合排序并显示不同的段落(分页) |
| | | * @param pageNo 页码 |
| | | * @param numPerPage 每页的条目数 |
| | | * @param comparator 比较器 |
| | | * @param colls 集合数组 |
| | | * @return 分业后的段落内容 |
| | | */ |
| | | // @SafeVarargs |
| | | // public static <T> List<T> sortPageAll2(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) { |
| | | // BoundedPriorityQueue<T> queue = new BoundedPriorityQueue<T>(pageNo * numPerPage); |
| | | // for (Collection<T> coll : colls) { |
| | | // queue.addAll(coll); |
| | | // } |
| | | // |
| | | // //第一页且数目少于第一页显示的数目 |
| | | // if(pageNo <=1 && queue.size() <= numPerPage) { |
| | | // return queue.toList(); |
| | | // } |
| | | // |
| | | // final int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage); |
| | | // return queue.toList().subList(startEnd[0], startEnd[1]); |
| | | // } |
| | | |
| | | /** |
| | | * 将Set排序(根据Entry的值) |
| | | * |
| | | * @param set 被排序的Set |
| | | * @return 排序后的Set |
| | | */ |
| | | public static List<Entry<Long, Long>> sortEntrySetToList(Set<Entry<Long, Long>> set) { |
| | | List<Entry<Long, Long>> list = new LinkedList<Entry<Long, Long>>(set); |
| | | Collections.sort(list, new Comparator<Entry<Long, Long>>(){ |
| | | |
| | | @Override |
| | | public int compare(Entry<Long, Long> o1, Entry<Long, Long> o2) { |
| | | if (o1.getValue() > o2.getValue()){ |
| | | return 1; |
| | | } |
| | | if (o1.getValue() < o2.getValue()){ |
| | | return -1; |
| | | } |
| | | return 0; |
| | | } |
| | | }); |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * 切取部分数据 |
| | | * |
| | | * @param <T> 集合元素类型 |
| | | * @param surplusAlaDatas 原数据 |
| | | * @param partSize 每部分数据的长度 |
| | | * @return 切取出的数据或null |
| | | */ |
| | | public static <T> List<T> popPart(Stack<T> surplusAlaDatas, int partSize) { |
| | | if (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){ |
| | | return null; |
| | | } |
| | | |
| | | final List<T> currentAlaDatas = new ArrayList<T>(); |
| | | int size = surplusAlaDatas.size(); |
| | | // 切割 |
| | | if (size > partSize) { |
| | | for (int i = 0; i < partSize; i++) { |
| | | currentAlaDatas.add(surplusAlaDatas.pop()); |
| | | } |
| | | } else { |
| | | for (int i = 0; i < size; i++) { |
| | | currentAlaDatas.add(surplusAlaDatas.pop()); |
| | | } |
| | | } |
| | | return currentAlaDatas; |
| | | } |
| | | |
| | | /** |
| | | * 切取部分数据 |
| | | * |
| | | * @param <T> 集合元素类型 |
| | | * @param surplusAlaDatas 原数据 |
| | | * @param partSize 每部分数据的长度 |
| | | * @return 切取出的数据或null |
| | | */ |
| | | public static <T> List<T> popPart(Deque<T> surplusAlaDatas, int partSize) { |
| | | if (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){ |
| | | return null; |
| | | } |
| | | |
| | | final List<T> currentAlaDatas = new ArrayList<T>(); |
| | | int size = surplusAlaDatas.size(); |
| | | // 切割 |
| | | if (size > partSize) { |
| | | for (int i = 0; i < partSize; i++) { |
| | | currentAlaDatas.add(surplusAlaDatas.pop()); |
| | | } |
| | | } else { |
| | | for (int i = 0; i < size; i++) { |
| | | currentAlaDatas.add(surplusAlaDatas.pop()); |
| | | } |
| | | } |
| | | return currentAlaDatas; |
| | | } |
| | | |
| | | /** |
| | | * 新建一个HashMap |
| | | * |
| | | * @return HashMap对象 |
| | | */ |
| | | public static <T, K> HashMap<T, K> newHashMap() { |
| | | return new HashMap<T, K>(); |
| | | } |
| | | |
| | | /** |
| | | * 新建一个HashMap |
| | | * @param size 初始大小,由于默认负载因子0.75,传入的size会实际初始大小为size / 0.75 |
| | | * @return HashMap对象 |
| | | */ |
| | | public static <T, K> HashMap<T, K> newHashMap(int size) { |
| | | return new HashMap<T, K>((int)(size / 0.75)); |
| | | } |
| | | |
| | | /** |
| | | * 新建一个HashSet |
| | | * |
| | | * @return HashSet对象 |
| | | */ |
| | | public static <T> HashSet<T> newHashSet() { |
| | | return new HashSet<T>(); |
| | | } |
| | | |
| | | /** |
| | | * 新建一个HashSet |
| | | * |
| | | * @return HashSet对象 |
| | | */ |
| | | @SafeVarargs |
| | | public static <T> HashSet<T> newHashSet(T... ts) { |
| | | HashSet<T> set = new HashSet<T>(); |
| | | for (T t : ts) { |
| | | set.add(t); |
| | | } |
| | | return set; |
| | | } |
| | | |
| | | /** |
| | | * 新建一个ArrayList |
| | | * |
| | | * @return ArrayList对象 |
| | | */ |
| | | public static <T> ArrayList<T> newArrayList() { |
| | | return new ArrayList<T>(); |
| | | } |
| | | |
| | | /** |
| | | * 新建一个ArrayList |
| | | * |
| | | * @return ArrayList对象 |
| | | */ |
| | | @SafeVarargs |
| | | public static <T> ArrayList<T> newArrayList(T... values) { |
| | | return new ArrayList<T>(Arrays.asList(values)); |
| | | } |
| | | |
| | | /** |
| | | * 将新元素添加到已有数组中<br/> |
| | | * 添加新元素会生成一个新的数组,不影响原数组 |
| | | * |
| | | * @param buffer 已有数组 |
| | | * @param newElement 新元素 |
| | | * @return 新数组 |
| | | */ |
| | | public static <T> T[] append(T[] buffer, T newElement) { |
| | | T[] t = resize(buffer, buffer.length + 1, newElement.getClass()); |
| | | t[buffer.length] = newElement; |
| | | return t; |
| | | } |
| | | |
| | | /** |
| | | * 生成一个新的重新设置大小的数组 |
| | | * |
| | | * @param buffer 原数组 |
| | | * @param newSize 新的数组大小 |
| | | * @param componentType 数组元素类型 |
| | | * @return 调整后的新数组 |
| | | */ |
| | | public static <T> T[] resize(T[] buffer, int newSize, Class<?> componentType) { |
| | | T[] newArray = newArray(componentType, newSize); |
| | | System.arraycopy(buffer, 0, newArray, 0, buffer.length >= newSize ? newSize : buffer.length); |
| | | return newArray; |
| | | } |
| | | |
| | | /** |
| | | * 新建一个空数组 |
| | | * @param componentType 元素类型 |
| | | * @param newSize 大小 |
| | | * @return 空数组 |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static <T> T[] newArray(Class<?> componentType, int newSize) { |
| | | return (T[]) Array.newInstance(componentType, newSize); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个新的重新设置大小的数组<br/> |
| | | * 新数组的类型为原数组的类型 |
| | | * |
| | | * @param buffer 原数组 |
| | | * @param newSize 新的数组大小 |
| | | * @return 调整后的新数组 |
| | | */ |
| | | public static <T> T[] resize(T[] buffer, int newSize) { |
| | | return resize(buffer, newSize, buffer.getClass().getComponentType()); |
| | | } |
| | | |
| | | /** |
| | | * 将多个数组合并在一起<br> |
| | | * 忽略null的数组 |
| | | * |
| | | * @param arrays 数组集合 |
| | | * @return 合并后的数组 |
| | | */ |
| | | @SafeVarargs |
| | | public static <T> T[] addAll(T[]... arrays) { |
| | | if (arrays.length == 1) { |
| | | return arrays[0]; |
| | | } |
| | | |
| | | int length = 0; |
| | | for (T[] array : arrays) { |
| | | if(array == null) { |
| | | continue; |
| | | } |
| | | length += array.length; |
| | | } |
| | | T[] result = newArray(arrays.getClass().getComponentType().getComponentType(), length); |
| | | |
| | | length = 0; |
| | | for (T[] array : arrays) { |
| | | if(array == null) { |
| | | continue; |
| | | } |
| | | System.arraycopy(array, 0, result, length, array.length); |
| | | length += array.length; |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 克隆数组 |
| | | * @param array 被克隆的数组 |
| | | * @return 新数组 |
| | | */ |
| | | public static <T> T[] clone(T[] array) { |
| | | if (array == null) { |
| | | return null; |
| | | } |
| | | return array.clone(); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个数字列表<br> |
| | | * 自动判定正序反序 |
| | | * @param excludedEnd 结束的数字(不包含) |
| | | * @return 数字列表 |
| | | */ |
| | | public static int[] range(int excludedEnd) { |
| | | return range(0, excludedEnd, 1); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个数字列表<br> |
| | | * 自动判定正序反序 |
| | | * @param includedStart 开始的数字(包含) |
| | | * @param excludedEnd 结束的数字(不包含) |
| | | * @return 数字列表 |
| | | */ |
| | | public static int[] range(int includedStart, int excludedEnd) { |
| | | return range(includedStart, excludedEnd, 1); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个数字列表<br> |
| | | * 自动判定正序反序 |
| | | * @param includedStart 开始的数字(包含) |
| | | * @param excludedEnd 结束的数字(不包含) |
| | | * @param step 步进 |
| | | * @return 数字列表 |
| | | */ |
| | | public static int[] range(int includedStart, int excludedEnd, int step) { |
| | | if(includedStart > excludedEnd) { |
| | | int tmp = includedStart; |
| | | includedStart = excludedEnd; |
| | | excludedEnd = tmp; |
| | | } |
| | | |
| | | if(step <=0) { |
| | | step = 1; |
| | | } |
| | | |
| | | int deviation = excludedEnd - includedStart; |
| | | int length = deviation / step; |
| | | if(deviation % step != 0) { |
| | | length += 1; |
| | | } |
| | | int[] range = new int[length]; |
| | | for(int i = 0; i < length; i++) { |
| | | range[i] = includedStart; |
| | | includedStart += step; |
| | | } |
| | | return range; |
| | | } |
| | | |
| | | /** |
| | | * 截取数组的部分 |
| | | * @param list 被截取的数组 |
| | | * @param start 开始位置(包含) |
| | | * @param end 结束位置(不包含) |
| | | * @return 截取后的数组,当开始位置超过最大时,返回null |
| | | */ |
| | | public static <T> List<T> sub(List<T> list, int start, int end) { |
| | | if(list == null || list.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | if(start < 0) { |
| | | start = 0; |
| | | } |
| | | if(end < 0) { |
| | | end = 0; |
| | | } |
| | | |
| | | if(start > end) { |
| | | int tmp = start; |
| | | start = end; |
| | | end = tmp; |
| | | } |
| | | |
| | | final int size = list.size(); |
| | | if(end > size) { |
| | | if(start >= size) { |
| | | return null; |
| | | } |
| | | end = size; |
| | | } |
| | | |
| | | return list.subList(start, end); |
| | | } |
| | | |
| | | /** |
| | | * 截取集合的部分 |
| | | * @param list 被截取的数组 |
| | | * @param start 开始位置(包含) |
| | | * @param end 结束位置(不包含) |
| | | * @return 截取后的数组,当开始位置超过最大时,返回null |
| | | */ |
| | | public static <T> List<T> sub(Collection<T> list, int start, int end) { |
| | | if(list == null || list.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | return sub(new ArrayList<T>(list), start, end); |
| | | } |
| | | |
| | | /** |
| | | * 数组是否为空 |
| | | * @param array 数组 |
| | | * @return 是否为空 |
| | | */ |
| | | public static <T> boolean isEmpty(T[] array) { |
| | | return array == null || array.length == 0; |
| | | } |
| | | |
| | | /** |
| | | * 数组是否为非空 |
| | | * @param array 数组 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static <T> boolean isNotEmpty(T[] array) { |
| | | return false == isEmpty(array); |
| | | } |
| | | |
| | | /** |
| | | * 集合是否为空 |
| | | * @param collection 集合 |
| | | * @return 是否为空 |
| | | */ |
| | | public static boolean isEmpty(Collection<?> collection) { |
| | | return collection == null || collection.isEmpty(); |
| | | } |
| | | |
| | | /** |
| | | * 集合是否为非空 |
| | | * @param collection 集合 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static boolean isNotEmpty(Collection<?> collection) { |
| | | return false == isEmpty(collection); |
| | | } |
| | | |
| | | /** |
| | | * Map是否为空 |
| | | * @param map 集合 |
| | | * @return 是否为空 |
| | | */ |
| | | public static boolean isEmpty(Map<?, ?> map) { |
| | | return map == null || map.isEmpty(); |
| | | } |
| | | |
| | | /** |
| | | * Map是否为非空 |
| | | * @param map 集合 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static <T> boolean isNotEmpty(Map<?, ?> map) { |
| | | return false == isEmpty(map); |
| | | } |
| | | |
| | | /** |
| | | * 映射键值(参考Python的zip()函数)<br> |
| | | * 例如:<br> |
| | | * keys = [a,b,c,d]<br> |
| | | * values = [1,2,3,4]<br> |
| | | * 则得到的Map是 {a=1, b=2, c=3, d=4}<br> |
| | | * 如果两个数组长度不同,则只对应最短部分 |
| | | * @param keys 键列表 |
| | | * @param values 值列表 |
| | | * @return Map |
| | | */ |
| | | public static <T, K> Map<T, K> zip(T[] keys, K[] values) { |
| | | if(isEmpty(keys) || isEmpty(values)) { |
| | | return null; |
| | | } |
| | | |
| | | final int size = Math.min(keys.length, values.length); |
| | | final Map<T, K> map = new HashMap<T, K>((int)(size / 0.75)); |
| | | for(int i = 0; i < size; i++) { |
| | | map.put(keys[i], values[i]); |
| | | } |
| | | |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 映射键值(参考Python的zip()函数)<br> |
| | | * 例如:<br> |
| | | * keys = a,b,c,d<br> |
| | | * values = 1,2,3,4<br> |
| | | * delimiter = , |
| | | * 则得到的Map是 {a=1, b=2, c=3, d=4}<br> |
| | | * 如果两个数组长度不同,则只对应最短部分 |
| | | * @param keys 键列表 |
| | | * @param values 值列表 |
| | | * @return Map |
| | | */ |
| | | public static Map<String, String> zip(String keys, String values, String delimiter) { |
| | | return zip(StrKit.split(keys, delimiter), StrKit.split(values, delimiter)); |
| | | } |
| | | |
| | | /** |
| | | * 映射键值(参考Python的zip()函数)<br> |
| | | * 例如:<br> |
| | | * keys = [a,b,c,d]<br> |
| | | * values = [1,2,3,4]<br> |
| | | * 则得到的Map是 {a=1, b=2, c=3, d=4}<br> |
| | | * 如果两个数组长度不同,则只对应最短部分 |
| | | * @param keys 键列表 |
| | | * @param values 值列表 |
| | | * @return Map |
| | | */ |
| | | public static <T, K> Map<T, K> zip(Collection<T> keys, Collection<K> values) { |
| | | if(isEmpty(keys) || isEmpty(values)) { |
| | | return null; |
| | | } |
| | | |
| | | final List<T> keyList = new ArrayList<T>(keys); |
| | | final List<K> valueList = new ArrayList<K>(values); |
| | | |
| | | final int size = Math.min(keys.size(), values.size()); |
| | | final Map<T, K> map = new HashMap<T, K>((int)(size / 0.75)); |
| | | for(int i = 0; i < size; i++) { |
| | | map.put(keyList.get(i), valueList.get(i)); |
| | | } |
| | | |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 数组中是否包含元素 |
| | | * @param array 数组 |
| | | * @param value 被检查的元素 |
| | | * @return 是否包含 |
| | | */ |
| | | public static <T> boolean contains(T[] array, T value) { |
| | | final Class<?> componetType = array.getClass().getComponentType(); |
| | | boolean isPrimitive = false; |
| | | if(null != componetType) { |
| | | isPrimitive = componetType.isPrimitive(); |
| | | } |
| | | for (T t : array) { |
| | | if(t == value) { |
| | | return true; |
| | | }else if(false == isPrimitive && null != value && value.equals(t)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 将Entry集合转换为HashMap |
| | | * @param entryCollection entry集合 |
| | | * @return Map |
| | | */ |
| | | public static <T, K> HashMap<T, K> toMap(Collection<Entry<T, K>> entryCollection) { |
| | | HashMap<T,K> map = new HashMap<T, K>(); |
| | | for (Entry<T, K> entry : entryCollection) { |
| | | map.put(entry.getKey(), entry.getValue()); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 将集合转换为排序后的TreeSet |
| | | * @param collection 集合 |
| | | * @param comparator 比较器 |
| | | * @return treeSet |
| | | */ |
| | | public static <T> TreeSet<T> toTreeSet(Collection<T> collection, Comparator<T> comparator){ |
| | | final TreeSet<T> treeSet = new TreeSet<T>(comparator); |
| | | for (T t : collection) { |
| | | treeSet.add(t); |
| | | } |
| | | return treeSet; |
| | | } |
| | | |
| | | /** |
| | | * 排序集合 |
| | | * @param collection 集合 |
| | | * @param comparator 比较器 |
| | | * @return treeSet |
| | | */ |
| | | public static <T> List<T> sort(Collection<T> collection, Comparator<T> comparator){ |
| | | List<T> list = new ArrayList<T>(collection); |
| | | Collections.sort(list, comparator); |
| | | return list; |
| | | } |
| | | |
| | | //------------------------------------------------------------------- 基本类型的数组转换为包装类型数组 |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Integer[] wrap(int... values){ |
| | | final int length = values.length; |
| | | Integer[] array = new Integer[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Long[] wrap(long... values){ |
| | | final int length = values.length; |
| | | Long[] array = new Long[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Character[] wrap(char... values){ |
| | | final int length = values.length; |
| | | Character[] array = new Character[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Byte[] wrap(byte... values){ |
| | | final int length = values.length; |
| | | Byte[] array = new Byte[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Short[] wrap(short... values){ |
| | | final int length = values.length; |
| | | Short[] array = new Short[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Float[] wrap(float... values){ |
| | | final int length = values.length; |
| | | Float[] array = new Float[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Double[] wrap(double... values){ |
| | | final int length = values.length; |
| | | Double[] array = new Double[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 将基本类型数组包装为包装类型 |
| | | * @param values 基本类型数组 |
| | | * @return 包装类型数组 |
| | | */ |
| | | public static Boolean[] wrap(boolean... values){ |
| | | final int length = values.length; |
| | | Boolean[] array = new Boolean[length]; |
| | | for(int i = 0; i < length; i++){ |
| | | array[i] = values[i]; |
| | | } |
| | | return array; |
| | | } |
| | | |
| | | /** |
| | | * 判定给定对象是否为数组类型 |
| | | * @param obj 对象 |
| | | * @return 是否为数组类型 |
| | | */ |
| | | public static boolean isArray(Object obj){ |
| | | return obj.getClass().isArray(); |
| | | } |
| | | |
| | | /** |
| | | * 数组或集合转String |
| | | * |
| | | * @param obj 集合或数组对象 |
| | | * @return 数组字符串,与集合转字符串格式相同 |
| | | */ |
| | | public static String toString(Object obj) { |
| | | if (null == obj) { |
| | | return null; |
| | | } |
| | | if (isArray(obj)) { |
| | | try { |
| | | return Arrays.deepToString((Object[]) obj); |
| | | } catch (Exception e) { |
| | | final String className = obj.getClass().getComponentType().getName(); |
| | | switch (className) { |
| | | case "long": |
| | | return Arrays.toString((long[]) obj); |
| | | case "int": |
| | | return Arrays.toString((int[]) obj); |
| | | case "short": |
| | | return Arrays.toString((short[]) obj); |
| | | case "char": |
| | | return Arrays.toString((char[]) obj); |
| | | case "byte": |
| | | return Arrays.toString((byte[]) obj); |
| | | case "boolean": |
| | | return Arrays.toString((boolean[]) obj); |
| | | case "float": |
| | | return Arrays.toString((float[]) obj); |
| | | case "double": |
| | | return Arrays.toString((double[]) obj); |
| | | default: |
| | | throw new ToolBoxException(e); |
| | | } |
| | | } |
| | | } |
| | | return obj.toString(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * 封装java.util.Date |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class DateTime extends Date{ |
| | | private static final long serialVersionUID = -5395712593979185936L; |
| | | |
| | | /** |
| | | * 转换JDK date为 DateTime |
| | | * @param date JDK Date |
| | | * @return DateTime |
| | | */ |
| | | public static DateTime parse(Date date) { |
| | | return new DateTime(date); |
| | | } |
| | | |
| | | /** |
| | | * 当前时间 |
| | | */ |
| | | public DateTime() { |
| | | super(); |
| | | } |
| | | |
| | | /** |
| | | * 给定日期的构造 |
| | | * @param date 日期 |
| | | */ |
| | | public DateTime(Date date) { |
| | | this(date.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 给定日期毫秒数的构造 |
| | | * @param timeMillis 日期毫秒数 |
| | | */ |
| | | public DateTime(long timeMillis) { |
| | | super(timeMillis); |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return DateTimeKit.formatDateTime(this); |
| | | } |
| | | |
| | | public String toString(String format) { |
| | | return DateTimeKit.format(this, format); |
| | | } |
| | | |
| | | /** |
| | | * @return 输出精确到毫秒的标准日期形式 |
| | | */ |
| | | public String toMsStr() { |
| | | return DateTimeKit.format(this, DateTimeKit.NORM_DATETIME_MS_PATTERN); |
| | | } |
| | | |
| | | /** |
| | | * @return java.util.Date |
| | | */ |
| | | public Date toDate() { |
| | | return new Date(this.getTime()); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import com.stylefeng.guns.core.support.exception.ToolBoxException; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.Locale; |
| | | |
| | | /** |
| | | * 时间工具类 |
| | | * @author xiaoleilu |
| | | */ |
| | | public class DateTimeKit { |
| | | /** 毫秒 */ |
| | | public final static long MS = 1; |
| | | /** 每秒钟的毫秒数 */ |
| | | public final static long SECOND_MS = MS * 1000; |
| | | /** 每分钟的毫秒数 */ |
| | | public final static long MINUTE_MS = SECOND_MS * 60; |
| | | /** 每小时的毫秒数 */ |
| | | public final static long HOUR_MS = MINUTE_MS * 60; |
| | | /** 每天的毫秒数 */ |
| | | public final static long DAY_MS = HOUR_MS * 24; |
| | | |
| | | /** 标准日期格式 */ |
| | | public final static String NORM_DATE_PATTERN = "yyyy-MM-dd"; |
| | | /** 标准时间格式 */ |
| | | public final static String NORM_TIME_PATTERN = "HH:mm:ss"; |
| | | /** 标准日期时间格式,精确到分 */ |
| | | public final static String NORM_DATETIME_MINUTE_PATTERN = "yyyy-MM-dd HH:mm"; |
| | | /** 标准日期时间格式,精确到秒 */ |
| | | public final static String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; |
| | | /** 标准日期时间格式,精确到毫秒 */ |
| | | public final static String NORM_DATETIME_MS_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS"; |
| | | /** HTTP头中日期时间格式 */ |
| | | public final static String HTTP_DATETIME_PATTERN = "EEE, dd MMM yyyy HH:mm:ss z"; |
| | | |
| | | /** 标准日期(不含时间)格式化器 */ |
| | | // private final static SimpleDateFormat NORM_DATE_FORMAT = new SimpleDateFormat(NORM_DATE_PATTERN); |
| | | private static ThreadLocal<SimpleDateFormat> NORM_DATE_FORMAT = new ThreadLocal<SimpleDateFormat>(){ |
| | | synchronized protected SimpleDateFormat initialValue() { |
| | | return new SimpleDateFormat(NORM_DATE_PATTERN); |
| | | }; |
| | | }; |
| | | /** 标准时间格式化器 */ |
| | | // private final static SimpleDateFormat NORM_TIME_FORMAT = new SimpleDateFormat(NORM_TIME_PATTERN); |
| | | private static ThreadLocal<SimpleDateFormat> NORM_TIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){ |
| | | synchronized protected SimpleDateFormat initialValue() { |
| | | return new SimpleDateFormat(NORM_TIME_PATTERN); |
| | | }; |
| | | }; |
| | | /** 标准日期时间格式化器 */ |
| | | // private final static SimpleDateFormat NORM_DATETIME_FORMAT = new SimpleDateFormat(NORM_DATETIME_PATTERN); |
| | | private static ThreadLocal<SimpleDateFormat> NORM_DATETIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){ |
| | | synchronized protected SimpleDateFormat initialValue() { |
| | | return new SimpleDateFormat(NORM_DATETIME_PATTERN); |
| | | }; |
| | | }; |
| | | /** HTTP日期时间格式化器 */ |
| | | // private final static SimpleDateFormat HTTP_DATETIME_FORMAT = new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US); |
| | | private static ThreadLocal<SimpleDateFormat> HTTP_DATETIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){ |
| | | synchronized protected SimpleDateFormat initialValue() { |
| | | return new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US); |
| | | }; |
| | | }; |
| | | |
| | | /** |
| | | * 当前时间,格式 yyyy-MM-dd HH:mm:ss |
| | | * |
| | | * @return 当前时间的标准形式字符串 |
| | | */ |
| | | public static String now() { |
| | | return formatDateTime(new DateTime()); |
| | | } |
| | | |
| | | /** |
| | | * 当前时间long |
| | | * |
| | | * @param isNano 是否为高精度时间 |
| | | * @return 时间 |
| | | */ |
| | | public static long current(boolean isNano) { |
| | | return isNano ? System.nanoTime() : System.currentTimeMillis(); |
| | | } |
| | | |
| | | /** |
| | | * 当前日期,格式 yyyy-MM-dd |
| | | * |
| | | * @return 当前日期的标准形式字符串 |
| | | */ |
| | | public static String today() { |
| | | return formatDate(new DateTime()); |
| | | } |
| | | |
| | | /** |
| | | * @return 当前月份 |
| | | */ |
| | | public static int thisMonth() { |
| | | return month(date()); |
| | | } |
| | | |
| | | /** |
| | | * @return 今年 |
| | | */ |
| | | public static int thisYear() { |
| | | return year(date()); |
| | | } |
| | | |
| | | /** |
| | | * @return 当前时间 |
| | | */ |
| | | public static DateTime date() { |
| | | return new DateTime(); |
| | | } |
| | | |
| | | /** |
| | | * Long类型时间转为Date |
| | | * |
| | | * @param date Long类型Date(Unix时间戳) |
| | | * @return 时间对象 |
| | | */ |
| | | public static DateTime date(long date) { |
| | | return new DateTime(date); |
| | | } |
| | | |
| | | /** |
| | | * 转换为Calendar对象 |
| | | * |
| | | * @param date 日期对象 |
| | | * @return Calendar对象 |
| | | */ |
| | | public static Calendar toCalendar(Date date) { |
| | | final Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(date); |
| | | return cal; |
| | | } |
| | | |
| | | /** |
| | | * 获得月份,从1月开始计数 |
| | | * |
| | | * @param date 日期 |
| | | * @return 月份 |
| | | */ |
| | | public static int month(Date date) { |
| | | return toCalendar(date).get(Calendar.MONTH) + 1; |
| | | } |
| | | |
| | | /** |
| | | * 获得年 |
| | | * |
| | | * @param date 日期 |
| | | * @return 年 |
| | | */ |
| | | public static int year(Date date) { |
| | | return toCalendar(date).get(Calendar.YEAR); |
| | | } |
| | | |
| | | /** |
| | | * 获得季节 |
| | | * |
| | | * @param date 日期 |
| | | * @return 第几个季节 |
| | | */ |
| | | public static int season(Date date) { |
| | | return toCalendar(date).get(Calendar.MONTH) / 3 + 1; |
| | | } |
| | | |
| | | /** |
| | | * 获得指定日期年份和季节<br> |
| | | * 格式:[20131]表示2013年第一季度 |
| | | * |
| | | * @param date 日期 |
| | | * @return Season ,类似于 20132 |
| | | */ |
| | | public static String yearAndSeason(Date date) { |
| | | return yearAndSeason(toCalendar(date)); |
| | | } |
| | | |
| | | /** |
| | | * 获得指定日期区间内的年份和季节<br> |
| | | * |
| | | * @param startDate 其实日期(包含) |
| | | * @param endDate 结束日期(包含) |
| | | * @return Season列表 ,元素类似于 20132 |
| | | */ |
| | | public static LinkedHashSet<String> yearAndSeasons(Date startDate, Date endDate) { |
| | | final LinkedHashSet<String> seasons = new LinkedHashSet<String>(); |
| | | if (startDate == null || endDate == null) { |
| | | return seasons; |
| | | } |
| | | |
| | | final Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(startDate); |
| | | while (true) { |
| | | // 如果开始时间超出结束时间,让结束时间为开始时间,处理完后结束循环 |
| | | if (startDate.after(endDate)) { |
| | | startDate = endDate; |
| | | } |
| | | |
| | | seasons.add(yearAndSeason(cal)); |
| | | |
| | | if (startDate.equals(endDate)) { |
| | | break; |
| | | } |
| | | |
| | | cal.add(Calendar.MONTH, 3); |
| | | startDate = cal.getTime(); |
| | | } |
| | | |
| | | return seasons; |
| | | } |
| | | |
| | | // ------------------------------------ Format start ---------------------------------------------- |
| | | /** |
| | | * 根据特定格式格式化日期 |
| | | * |
| | | * @param date 被格式化的日期 |
| | | * @param format 格式 |
| | | * @return 格式化后的字符串 |
| | | */ |
| | | public static String format(Date date, String format) { |
| | | return new SimpleDateFormat(format).format(date); |
| | | } |
| | | |
| | | /** |
| | | * 格式 yyyy-MM-dd HH:mm:ss |
| | | * |
| | | * @param date 被格式化的日期 |
| | | * @return 格式化后的日期 |
| | | */ |
| | | public static String formatDateTime(Date date) { |
| | | if(null == date){ |
| | | return null; |
| | | } |
| | | return NORM_DATETIME_FORMAT.get().format(date); |
| | | } |
| | | |
| | | /** |
| | | * 格式 yyyy-MM-dd |
| | | * |
| | | * @param date 被格式化的日期 |
| | | * @return 格式化后的字符串 |
| | | */ |
| | | public static String formatDate(Date date) { |
| | | if(null == date){ |
| | | return null; |
| | | } |
| | | return NORM_DATE_FORMAT.get().format(date); |
| | | } |
| | | |
| | | /** |
| | | * 格式化为Http的标准日期格式 |
| | | * |
| | | * @param date 被格式化的日期 |
| | | * @return HTTP标准形式日期字符串 |
| | | */ |
| | | public static String formatHttpDate(Date date) { |
| | | if(null == date){ |
| | | return null; |
| | | } |
| | | return HTTP_DATETIME_FORMAT.get().format(date); |
| | | } |
| | | // ------------------------------------ Format end ---------------------------------------------- |
| | | |
| | | // ------------------------------------ Parse start ---------------------------------------------- |
| | | |
| | | /** |
| | | * 构建DateTime对象 |
| | | * |
| | | * @param dateStr Date字符串 |
| | | * @param simpleDateFormat 格式化器 |
| | | * @return DateTime对象 |
| | | */ |
| | | public static DateTime parse(String dateStr, SimpleDateFormat simpleDateFormat) { |
| | | try { |
| | | return new DateTime(simpleDateFormat.parse(dateStr)); |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Parse [{}] with format [{}] error!", dateStr, simpleDateFormat.toPattern()), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 将特定格式的日期转换为Date对象 |
| | | * |
| | | * @param dateString 特定格式的日期 |
| | | * @param format 格式,例如yyyy-MM-dd |
| | | * @return 日期对象 |
| | | */ |
| | | public static DateTime parse(String dateString, String format) { |
| | | return parse(dateString, new SimpleDateFormat(format)); |
| | | } |
| | | |
| | | /** |
| | | * 格式yyyy-MM-dd HH:mm:ss |
| | | * |
| | | * @param dateString 标准形式的时间字符串 |
| | | * @return 日期对象 |
| | | */ |
| | | public static DateTime parseDateTime(String dateString) { |
| | | return parse(dateString, NORM_DATETIME_FORMAT.get()); |
| | | } |
| | | |
| | | /** |
| | | * 格式yyyy-MM-dd |
| | | * |
| | | * @param dateString 标准形式的日期字符串 |
| | | * @return 日期对象 |
| | | */ |
| | | public static DateTime parseDate(String dateString) { |
| | | return parse(dateString, NORM_DATE_FORMAT.get()); |
| | | } |
| | | |
| | | /** |
| | | * 格式HH:mm:ss |
| | | * |
| | | * @param timeString 标准形式的日期字符串 |
| | | * @return 日期对象 |
| | | */ |
| | | public static DateTime parseTime(String timeString) { |
| | | return parse(timeString, NORM_TIME_FORMAT.get()); |
| | | } |
| | | |
| | | /** |
| | | * 格式:<br> |
| | | * 1、yyyy-MM-dd HH:mm:ss<br> |
| | | * 2、yyyy-MM-dd<br> |
| | | * 3、HH:mm:ss<br> |
| | | * 4、yyyy-MM-dd HH:mm 5、yyyy-MM-dd HH:mm:ss.SSS |
| | | * |
| | | * @param dateStr 日期字符串 |
| | | * @return 日期 |
| | | */ |
| | | public static DateTime parse(String dateStr) { |
| | | if (null == dateStr) { |
| | | return null; |
| | | } |
| | | dateStr = dateStr.trim(); |
| | | int length = dateStr.length(); |
| | | try { |
| | | if (length == NORM_DATETIME_PATTERN.length()) { |
| | | return parseDateTime(dateStr); |
| | | } else if (length == NORM_DATE_PATTERN.length()) { |
| | | return parseDate(dateStr); |
| | | } else if (length == NORM_TIME_PATTERN.length()) { |
| | | return parseTime(dateStr); |
| | | } else if (length == NORM_DATETIME_MINUTE_PATTERN.length()) { |
| | | return parse(dateStr, NORM_DATETIME_MINUTE_PATTERN); |
| | | } else if (length >= NORM_DATETIME_MS_PATTERN.length() - 2) { |
| | | return parse(dateStr, NORM_DATETIME_MS_PATTERN); |
| | | } |
| | | } catch (Exception e) { |
| | | throw new ToolBoxException(StrKit.format("Parse [{}] with format normal error!", dateStr)); |
| | | } |
| | | |
| | | // 没有更多匹配的时间格式 |
| | | throw new ToolBoxException(StrKit.format(" [{}] format is not fit for date pattern!", dateStr)); |
| | | } |
| | | // ------------------------------------ Parse end ---------------------------------------------- |
| | | |
| | | // ------------------------------------ Offset start ---------------------------------------------- |
| | | /** |
| | | * 获取某天的开始时间 |
| | | * |
| | | * @param date 日期 |
| | | * @return 某天的开始时间 |
| | | */ |
| | | public static DateTime getBeginTimeOfDay(Date date) { |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.setTime(date); |
| | | calendar.set(Calendar.HOUR_OF_DAY, 0); |
| | | calendar.set(Calendar.MINUTE, 0); |
| | | calendar.set(Calendar.SECOND, 0); |
| | | calendar.set(Calendar.MILLISECOND, 0); |
| | | return new DateTime(calendar.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 获取某天的结束时间 |
| | | * |
| | | * @param date 日期 |
| | | * @return 某天的结束时间 |
| | | */ |
| | | public static DateTime getEndTimeOfDay(Date date) { |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.setTime(date); |
| | | calendar.set(Calendar.HOUR_OF_DAY, 23); |
| | | calendar.set(Calendar.MINUTE, 59); |
| | | calendar.set(Calendar.SECOND, 59); |
| | | calendar.set(Calendar.MILLISECOND, 999); |
| | | return new DateTime(calendar.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 昨天 |
| | | * |
| | | * @return 昨天 |
| | | */ |
| | | public static DateTime yesterday() { |
| | | return offsiteDay(new DateTime(), -1); |
| | | } |
| | | |
| | | /** |
| | | * 上周 |
| | | * |
| | | * @return 上周 |
| | | */ |
| | | public static DateTime lastWeek() { |
| | | return offsiteWeek(new DateTime(), -1); |
| | | } |
| | | |
| | | /** |
| | | * 上个月 |
| | | * |
| | | * @return 上个月 |
| | | */ |
| | | public static DateTime lastMouth() { |
| | | return offsiteMonth(new DateTime(), -1); |
| | | } |
| | | |
| | | /** |
| | | * 偏移天 |
| | | * |
| | | * @param date 日期 |
| | | * @param offsite 偏移天数,正数向未来偏移,负数向历史偏移 |
| | | * @return 偏移后的日期 |
| | | */ |
| | | public static DateTime offsiteDay(Date date, int offsite) { |
| | | return offsiteDate(date, Calendar.DAY_OF_YEAR, offsite); |
| | | } |
| | | |
| | | /** |
| | | * 偏移周 |
| | | * |
| | | * @param date 日期 |
| | | * @param offsite 偏移周数,正数向未来偏移,负数向历史偏移 |
| | | * @return 偏移后的日期 |
| | | */ |
| | | public static DateTime offsiteWeek(Date date, int offsite) { |
| | | return offsiteDate(date, Calendar.WEEK_OF_YEAR, offsite); |
| | | } |
| | | |
| | | /** |
| | | * 偏移月 |
| | | * |
| | | * @param date 日期 |
| | | * @param offsite 偏移月数,正数向未来偏移,负数向历史偏移 |
| | | * @return 偏移后的日期 |
| | | */ |
| | | public static DateTime offsiteMonth(Date date, int offsite) { |
| | | return offsiteDate(date, Calendar.MONTH, offsite); |
| | | } |
| | | |
| | | /** |
| | | * 获取指定日期偏移指定时间后的时间 |
| | | * |
| | | * @param date 基准日期 |
| | | * @param calendarField 偏移的粒度大小(小时、天、月等)使用Calendar中的常数 |
| | | * @param offsite 偏移量,正数为向后偏移,负数为向前偏移 |
| | | * @return 偏移后的日期 |
| | | */ |
| | | public static DateTime offsiteDate(Date date, int calendarField, int offsite) { |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(date); |
| | | cal.add(calendarField, offsite); |
| | | return new DateTime(cal.getTime()); |
| | | } |
| | | // ------------------------------------ Offset end ---------------------------------------------- |
| | | |
| | | /** |
| | | * 判断两个日期相差的时长<br/> |
| | | * 返回 minuend - subtrahend 的差 |
| | | * |
| | | * @param subtrahend 减数日期 |
| | | * @param minuend 被减数日期 |
| | | * @param diffField 相差的选项:相差的天、小时 |
| | | * @return 日期差 |
| | | */ |
| | | public static long diff(Date subtrahend, Date minuend, long diffField) { |
| | | long diff = minuend.getTime() - subtrahend.getTime(); |
| | | return diff / diffField; |
| | | } |
| | | |
| | | /** |
| | | * 计时,常用于记录某段代码的执行时间,单位:纳秒 |
| | | * |
| | | * @param preTime 之前记录的时间 |
| | | * @return 时间差,纳秒 |
| | | */ |
| | | public static long spendNt(long preTime) { |
| | | return System.nanoTime() - preTime; |
| | | } |
| | | |
| | | /** |
| | | * 计时,常用于记录某段代码的执行时间,单位:毫秒 |
| | | * |
| | | * @param preTime 之前记录的时间 |
| | | * @return 时间差,毫秒 |
| | | */ |
| | | public static long spendMs(long preTime) { |
| | | return System.currentTimeMillis() - preTime; |
| | | } |
| | | |
| | | /** |
| | | * 格式化成yyMMddHHmm后转换为int型 |
| | | * |
| | | * @param date 日期 |
| | | * @return int |
| | | */ |
| | | public static int toIntSecond(Date date) { |
| | | return Integer.parseInt(format(date, "yyMMddHHmm")); |
| | | } |
| | | |
| | | /** |
| | | * 计算指定指定时间区间内的周数 |
| | | * |
| | | * @param start 开始时间 |
| | | * @param end 结束时间 |
| | | * @return 周数 |
| | | */ |
| | | public static int weekCount(Date start, Date end) { |
| | | final Calendar startCalendar = Calendar.getInstance(); |
| | | startCalendar.setTime(start); |
| | | final Calendar endCalendar = Calendar.getInstance(); |
| | | endCalendar.setTime(end); |
| | | |
| | | final int startWeekofYear = startCalendar.get(Calendar.WEEK_OF_YEAR); |
| | | final int endWeekofYear = endCalendar.get(Calendar.WEEK_OF_YEAR); |
| | | |
| | | int count = endWeekofYear - startWeekofYear + 1; |
| | | |
| | | if (Calendar.SUNDAY != startCalendar.get(Calendar.DAY_OF_WEEK)) { |
| | | count--; |
| | | } |
| | | |
| | | return count; |
| | | } |
| | | |
| | | /** |
| | | * 计时器<br> |
| | | * 计算某个过程话费的时间,精确到毫秒 |
| | | * |
| | | * @return Timer |
| | | */ |
| | | public static Timer timer() { |
| | | return new Timer(); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 生日转为年龄,计算法定年龄 |
| | | * @param birthDay 生日,标准日期字符串 |
| | | * @return 年龄 |
| | | * @throws Exception |
| | | */ |
| | | public static int ageOfNow(String birthDay) { |
| | | return ageOfNow(parse(birthDay)); |
| | | } |
| | | |
| | | /** |
| | | * 生日转为年龄,计算法定年龄 |
| | | * @param birthDay 生日 |
| | | * @return 年龄 |
| | | * @throws Exception |
| | | */ |
| | | public static int ageOfNow(Date birthDay) { |
| | | return age(birthDay,date()); |
| | | } |
| | | |
| | | /** |
| | | * 计算相对于dateToCompare的年龄,长用于计算指定生日在某年的年龄 |
| | | * @param birthDay 生日 |
| | | * @param dateToCompare 需要对比的日期 |
| | | * @return 年龄 |
| | | * @throws Exception |
| | | */ |
| | | public static int age(Date birthDay, Date dateToCompare) { |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(dateToCompare); |
| | | |
| | | if (cal.before(birthDay)) { |
| | | throw new IllegalArgumentException(StrKit.format("Birthday is after date {}!", formatDate(dateToCompare))); |
| | | } |
| | | |
| | | int year = cal.get(Calendar.YEAR); |
| | | int month = cal.get(Calendar.MONTH); |
| | | int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH); |
| | | |
| | | cal.setTime(birthDay); |
| | | int age = year - cal.get(Calendar.YEAR); |
| | | |
| | | int monthBirth = cal.get(Calendar.MONTH); |
| | | if (month == monthBirth) { |
| | | int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH); |
| | | if (dayOfMonth < dayOfMonthBirth) { |
| | | //如果生日在当月,但是未达到生日当天的日期,年龄减一 |
| | | age--; |
| | | } |
| | | } else if (month < monthBirth){ |
| | | //如果当前月份未达到生日的月份,年龄计算减一 |
| | | age--; |
| | | } |
| | | |
| | | return age; |
| | | } |
| | | |
| | | /** |
| | | * 计时器<br> |
| | | * 计算某个过程话费的时间,精确到毫秒 |
| | | * |
| | | * @author Looly |
| | | * |
| | | */ |
| | | public static class Timer { |
| | | private long time; |
| | | private boolean isNano; |
| | | |
| | | public Timer() { |
| | | this(false); |
| | | } |
| | | |
| | | public Timer(boolean isNano) { |
| | | this.isNano = isNano; |
| | | start(); |
| | | } |
| | | |
| | | /** |
| | | * @return 开始计时并返回当前时间 |
| | | */ |
| | | public long start() { |
| | | time = current(isNano); |
| | | return time; |
| | | } |
| | | |
| | | /** |
| | | * @return 重新计时并返回从开始到当前的持续时间 |
| | | */ |
| | | public long durationRestart() { |
| | | long now = current(isNano); |
| | | long d = now - time; |
| | | time = now; |
| | | return d; |
| | | } |
| | | |
| | | /** |
| | | * @return 从开始到当前的持续时间 |
| | | */ |
| | | public long duration() { |
| | | return current(isNano) - time; |
| | | } |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------ Private method start |
| | | /** |
| | | * 获得指定日期年份和季节<br> |
| | | * 格式:[20131]表示2013年第一季度 |
| | | * |
| | | * @param cal 日期 |
| | | */ |
| | | private static String yearAndSeason(Calendar cal) { |
| | | return new StringBuilder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString(); |
| | | } |
| | | // ------------------------------------------------------------------------ Private method end |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.nio.charset.Charset; |
| | | |
| | | /** |
| | | * 十六进制(简写为hex或下标16)在数学中是一种逢16进1的进位制,一般用数字0到9和字母A到F表示(其中:A~F即10~15)。<br> |
| | | * 例如十进制数57,在二进制写作111001,在16进制写作39。<br> |
| | | * 像java,c这样的语言为了区分十六进制和十进制数值,会在十六进制数的前面加上 0x,比如0x20是十进制的32,而不是十进制的20<br> |
| | | * |
| | | * 参考:https://my.oschina.net/xinxingegeya/blog/287476 |
| | | * |
| | | * @author Looly |
| | | * |
| | | */ |
| | | public class HexKit { |
| | | |
| | | /** |
| | | * 用于建立十六进制字符的输出的小写字符数组 |
| | | */ |
| | | private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; |
| | | /** |
| | | * 用于建立十六进制字符的输出的大写字符数组 |
| | | */ |
| | | private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; |
| | | |
| | | //---------------------------------------------------------------------------------------------------- encode |
| | | /** |
| | | * 将字节数组转换为十六进制字符数组 |
| | | * |
| | | * @param data byte[] |
| | | * @return 十六进制char[] |
| | | */ |
| | | public static char[] encodeHex(byte[] data) { |
| | | return encodeHex(data, true); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符数组 |
| | | * |
| | | * @param str 字符串 |
| | | * @param charset 编码 |
| | | * @return 十六进制char[] |
| | | */ |
| | | public static char[] encodeHex(String str, Charset charset) { |
| | | return encodeHex(StrKit.getBytes(str, charset), true); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符数组 |
| | | * |
| | | * @param data byte[] |
| | | * @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式 |
| | | * @return 十六进制char[] |
| | | */ |
| | | public static char[] encodeHex(byte[] data, boolean toLowerCase) { |
| | | return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符串 |
| | | * |
| | | * @param data byte[] |
| | | * @return 十六进制String |
| | | */ |
| | | public static String encodeHexStr(byte[] data) { |
| | | return encodeHexStr(data, true); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符串 |
| | | * |
| | | * @param data byte[] |
| | | * @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式 |
| | | * @return 十六进制String |
| | | */ |
| | | public static String encodeHexStr(byte[] data, boolean toLowerCase) { |
| | | return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); |
| | | } |
| | | |
| | | //---------------------------------------------------------------------------------------------------- decode |
| | | /** |
| | | * 将十六进制字符数组转换为字符串 |
| | | * |
| | | * @param hexStr 十六进制String |
| | | * @param charset 编码 |
| | | * @return 字符串 |
| | | */ |
| | | public static String decodeHexStr(String hexStr, Charset charset) { |
| | | if(StrKit.isEmpty(hexStr)){ |
| | | return hexStr; |
| | | } |
| | | return decodeHexStr(hexStr.toCharArray(), charset); |
| | | } |
| | | |
| | | /** |
| | | * 将十六进制字符数组转换为字符串 |
| | | * |
| | | * @param hexData 十六进制char[] |
| | | * @param charset 编码 |
| | | * @return 字符串 |
| | | */ |
| | | public static String decodeHexStr(char[] hexData, Charset charset) { |
| | | return StrKit.str(decodeHex(hexData), charset); |
| | | } |
| | | |
| | | /** |
| | | * 将十六进制字符数组转换为字节数组 |
| | | * |
| | | * @param hexData 十六进制char[] |
| | | * @return byte[] |
| | | * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常 |
| | | */ |
| | | public static byte[] decodeHex(char[] hexData) { |
| | | |
| | | int len = hexData.length; |
| | | |
| | | if ((len & 0x01) != 0) { |
| | | throw new RuntimeException("Odd number of characters."); |
| | | } |
| | | |
| | | byte[] out = new byte[len >> 1]; |
| | | |
| | | // two characters form the hex value. |
| | | for (int i = 0, j = 0; j < len; i++) { |
| | | int f = toDigit(hexData[j], j) << 4; |
| | | j++; |
| | | f = f | toDigit(hexData[j], j); |
| | | j++; |
| | | out[i] = (byte) (f & 0xFF); |
| | | } |
| | | |
| | | return out; |
| | | } |
| | | |
| | | //---------------------------------------------------------------------------------------- Private method start |
| | | /** |
| | | * 将字节数组转换为十六进制字符串 |
| | | * |
| | | * @param data byte[] |
| | | * @param toDigits 用于控制输出的char[] |
| | | * @return 十六进制String |
| | | */ |
| | | private static String encodeHexStr(byte[] data, char[] toDigits) { |
| | | return new String(encodeHex(data, toDigits)); |
| | | } |
| | | |
| | | /** |
| | | * 将字节数组转换为十六进制字符数组 |
| | | * |
| | | * @param data byte[] |
| | | * @param toDigits 用于控制输出的char[] |
| | | * @return 十六进制char[] |
| | | */ |
| | | private static char[] encodeHex(byte[] data, char[] toDigits) { |
| | | int l = data.length; |
| | | char[] out = new char[l << 1]; |
| | | // two characters form the hex value. |
| | | for (int i = 0, j = 0; i < l; i++) { |
| | | out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; |
| | | out[j++] = toDigits[0x0F & data[i]]; |
| | | } |
| | | return out; |
| | | } |
| | | |
| | | /** |
| | | * 将十六进制字符转换成一个整数 |
| | | * |
| | | * @param ch 十六进制char |
| | | * @param index 十六进制字符在字符数组中的位置 |
| | | * @return 一个整数 |
| | | * @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常 |
| | | */ |
| | | private static int toDigit(char ch, int index) { |
| | | int digit = Character.digit(ch, 16); |
| | | if (digit == -1) { |
| | | throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index); |
| | | } |
| | | return digit; |
| | | } |
| | | //---------------------------------------------------------------------------------------- Private method end |
| | | |
| | | |
| | | |
| | | /** |
| | | * 2进制转16进制 |
| | | * @param bString 2进制字符串 |
| | | * @return |
| | | */ |
| | | public static String binary2Hex(String bString) { |
| | | if (bString == null || bString.equals("") || bString.length() % 8 != 0) |
| | | return null; |
| | | StringBuffer tmp = new StringBuffer(); |
| | | int iTmp = 0; |
| | | for (int i = 0; i < bString.length(); i += 4) { |
| | | iTmp = 0; |
| | | for (int j = 0; j < 4; j++) { |
| | | iTmp += Integer.parseInt(bString.substring(i + j, i + j + 1)) << (4 - j - 1); |
| | | } |
| | | tmp.append(Integer.toHexString(iTmp)); |
| | | } |
| | | return tmp.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 16进制转2进制 |
| | | * @param hexString |
| | | * @return |
| | | */ |
| | | public static String hex2Binary(String hexString) { |
| | | if (hexString == null || hexString.length() % 2 != 0) |
| | | return null; |
| | | String bString = "", tmp; |
| | | for (int i = 0; i < hexString.length(); i++) { |
| | | tmp = "0000" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16)); |
| | | bString += tmp.substring(tmp.length() - 4); |
| | | } |
| | | return bString; |
| | | } |
| | | |
| | | /** |
| | | * 将二进制转换成16进制 |
| | | * @param buf |
| | | * @return |
| | | */ |
| | | public static String binary2Hex(byte buf[]) { |
| | | StringBuffer sb = new StringBuffer(); |
| | | for (int i = 0; i < buf.length; i++) { |
| | | String hex = Integer.toHexString(buf[i] & 0xFF); |
| | | if (hex.length() == 1) { |
| | | hex = '0' + hex; |
| | | } |
| | | sb.append(hex.toUpperCase()); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 将16进制转换为二进制 |
| | | * @param hexStr |
| | | * @return |
| | | */ |
| | | public static byte[] hex2Byte(String hexStr) { |
| | | if (hexStr.length() < 1) |
| | | return null; |
| | | byte[] result = new byte[hexStr.length() / 2]; |
| | | for (int i = 0; i < hexStr.length() / 2; i++) { |
| | | int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); |
| | | int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); |
| | | result[i] = (byte) (high * 16 + low); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /** |
| | | * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com). |
| | | * <p> |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * <p> |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * <p> |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import org.springframework.web.context.request.RequestContextHolder; |
| | | import org.springframework.web.context.request.ServletRequestAttributes; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.BufferedReader; |
| | | import java.io.IOException; |
| | | import java.io.InputStreamReader; |
| | | import java.io.PrintWriter; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | import java.util.Enumeration; |
| | | import java.net.URLEncoder; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public class HttpKit { |
| | | |
| | | public static String getIp(){ |
| | | return HttpKit.getRequest().getRemoteHost(); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有请求的值 |
| | | */ |
| | | public static Map<String, String> getRequestParameters() { |
| | | HashMap<String, String> values = new HashMap<>(); |
| | | HttpServletRequest request = HttpKit.getRequest(); |
| | | Enumeration enums = request.getParameterNames(); |
| | | while ( enums.hasMoreElements()){ |
| | | String paramName = (String) enums.nextElement(); |
| | | String paramValue = request.getParameter(paramName); |
| | | values.put(paramName, paramValue); |
| | | } |
| | | return values; |
| | | } |
| | | |
| | | /** |
| | | * 获取 HttpServletRequest |
| | | */ |
| | | public static HttpServletResponse getResponse() { |
| | | HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取 包装防Xss Sql注入的 HttpServletRequest |
| | | * @return request |
| | | */ |
| | | public static HttpServletRequest getRequest() { |
| | | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); |
| | | return new WafRequestWrapper(request); |
| | | } |
| | | |
| | | /** |
| | | * 向指定URL发送GET方法的请求 |
| | | * |
| | | * @param url 发送请求的URL |
| | | * @param param 请求参数 |
| | | * @return URL 所代表远程资源的响应结果 |
| | | */ |
| | | public static String sendGet(String url, Map<String, String> param) { |
| | | String result = ""; |
| | | BufferedReader in = null; |
| | | try { |
| | | StringBuffer query = new StringBuffer(); |
| | | |
| | | for (Map.Entry<String, String> kv : param.entrySet()) { |
| | | query.append(URLEncoder.encode(kv.getKey(), "UTF-8") + "="); |
| | | query.append(URLEncoder.encode(kv.getValue(), "UTF-8") + "&"); |
| | | } |
| | | if (query.lastIndexOf("&") > 0) { |
| | | query.deleteCharAt(query.length() - 1); |
| | | } |
| | | |
| | | String urlNameString = url + "?" + query.toString(); |
| | | URL realUrl = new URL(urlNameString); |
| | | // 打开和URL之间的连接 |
| | | URLConnection connection = realUrl.openConnection(); |
| | | // 设置通用的请求属性 |
| | | connection.setRequestProperty("accept", "*/*"); |
| | | connection.setRequestProperty("connection", "Keep-Alive"); |
| | | connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); |
| | | // 建立实际的连接 |
| | | connection.connect(); |
| | | // 获取所有响应头字段 |
| | | Map<String, List<String>> map = connection.getHeaderFields(); |
| | | // 遍历所有的响应头字段 |
| | | for (String key : map.keySet()) { |
| | | System.out.println(key + "--->" + map.get(key)); |
| | | } |
| | | // 定义 BufferedReader输入流来读取URL的响应 |
| | | in = new BufferedReader(new InputStreamReader(connection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | result += line; |
| | | } |
| | | } catch (Exception e) { |
| | | System.out.println("发送GET请求出现异常!" + e); |
| | | e.printStackTrace(); |
| | | } |
| | | // 使用finally块来关闭输入流 |
| | | finally { |
| | | try { |
| | | if (in != null) { |
| | | in.close(); |
| | | } |
| | | } catch (Exception e2) { |
| | | e2.printStackTrace(); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 向指定 URL 发送POST方法的请求 |
| | | * |
| | | * @param url 发送请求的 URL |
| | | * @param param 请求参数 |
| | | * @return 所代表远程资源的响应结果 |
| | | */ |
| | | public static String sendPost(String url, Map<String, String> param) { |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | String result = ""; |
| | | try { |
| | | String para = ""; |
| | | for (String key : param.keySet()) { |
| | | para += (key + "=" + param.get(key) + "&"); |
| | | } |
| | | if (para.lastIndexOf("&") > 0) { |
| | | para = para.substring(0, para.length() - 1); |
| | | } |
| | | String urlNameString = url + "?" + para; |
| | | URL realUrl = new URL(urlNameString); |
| | | // 打开和URL之间的连接 |
| | | URLConnection conn = realUrl.openConnection(); |
| | | // 设置通用的请求属性 |
| | | conn.setRequestProperty("accept", "*/*"); |
| | | conn.setRequestProperty("connection", "Keep-Alive"); |
| | | conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); |
| | | // 发送POST请求必须设置如下两行 |
| | | conn.setDoOutput(true); |
| | | conn.setDoInput(true); |
| | | // 获取URLConnection对象对应的输出流 |
| | | out = new PrintWriter(conn.getOutputStream()); |
| | | // 发送请求参数 |
| | | out.print(param); |
| | | // flush输出流的缓冲 |
| | | out.flush(); |
| | | // 定义BufferedReader输入流来读取URL的响应 |
| | | in = new BufferedReader(new InputStreamReader(conn.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | result += line; |
| | | } |
| | | } catch (Exception e) { |
| | | System.out.println("发送 POST 请求出现异常!" + e); |
| | | e.printStackTrace(); |
| | | } |
| | | // 使用finally块来关闭输出流、输入流 |
| | | finally { |
| | | try { |
| | | if (out != null) { |
| | | out.close(); |
| | | } |
| | | if (in != null) { |
| | | in.close(); |
| | | } |
| | | } catch (IOException ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | /** |
| | | * 一些通用的函数 |
| | | * |
| | | * @author Looly |
| | | * |
| | | */ |
| | | public class ObjectKit { |
| | | /** |
| | | * 比较两个对象是否相等。<br> |
| | | * 相同的条件有两个,满足其一即可:<br> |
| | | * 1. obj1 == null && obj2 == null; 2. obj1.equals(obj2) |
| | | * |
| | | * @param obj1 对象1 |
| | | * @param obj2 对象2 |
| | | * @return 是否相等 |
| | | */ |
| | | public static boolean equals(Object obj1, Object obj2) { |
| | | return (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | /** |
| | | * 分页工具类 |
| | | * |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class PageKit { |
| | | |
| | | /** |
| | | * 将页数和每页条目数转换为开始位置和结束位置<br> |
| | | * 此方法用于不包括结束位置的分页方法<br> |
| | | * 例如:<br> |
| | | * 页码:1,每页10 -> [0, 10]<br> |
| | | * 页码:2,每页10 -> [10, 20]<br> |
| | | * 。。。<br> |
| | | * |
| | | * @param pageNo |
| | | * 页码(从1计数) |
| | | * @param countPerPage |
| | | * 每页条目数 |
| | | * @return 第一个数为开始位置,第二个数为结束位置 |
| | | */ |
| | | public static int[] transToStartEnd(int pageNo, int countPerPage) { |
| | | if (pageNo < 1) { |
| | | pageNo = 1; |
| | | } |
| | | |
| | | if (countPerPage < 1) { |
| | | countPerPage = 0; |
| | | // LogKit.warn("Count per page [" + countPerPage + "] is not valid!"); |
| | | } |
| | | |
| | | int start = (pageNo - 1) * countPerPage; |
| | | int end = start + countPerPage; |
| | | |
| | | return new int[] { start, end }; |
| | | } |
| | | |
| | | /** |
| | | * 根据总数计算总页数 |
| | | * |
| | | * @param totalCount |
| | | * 总数 |
| | | * @param numPerPage |
| | | * 每页数 |
| | | * @return 总页数 |
| | | */ |
| | | public static int totalPage(int totalCount, int numPerPage) { |
| | | if (numPerPage == 0) { |
| | | return 0; |
| | | } |
| | | return totalCount % numPerPage == 0 ? (totalCount / numPerPage) |
| | | : (totalCount / numPerPage + 1); |
| | | } |
| | | } |
New file |
| | |
| | | package com.stylefeng.guns.core.support; |
| | | |
| | | import java.io.StringReader; |
| | | import java.io.StringWriter; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.nio.ByteBuffer; |
| | | import java.nio.charset.Charset; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Map.Entry; |
| | | |
| | | /** |
| | | * 字符串工具类 |
| | | * |
| | | * @author xiaoleilu |
| | | * |
| | | */ |
| | | public class StrKit { |
| | | |
| | | public static final String SPACE = " "; |
| | | public static final String DOT = "."; |
| | | public static final String SLASH = "/"; |
| | | public static final String BACKSLASH = "\\"; |
| | | public static final String EMPTY = ""; |
| | | public static final String CRLF = "\r\n"; |
| | | public static final String NEWLINE = "\n"; |
| | | public static final String UNDERLINE = "_"; |
| | | public static final String COMMA = ","; |
| | | |
| | | public static final String HTML_NBSP = " "; |
| | | public static final String HTML_AMP = "&"; |
| | | public static final String HTML_QUOTE = """; |
| | | public static final String HTML_LT = "<"; |
| | | public static final String HTML_GT = ">"; |
| | | |
| | | public static final String EMPTY_JSON = "{}"; |
| | | |
| | | |
| | | /** |
| | | * 首字母变小写 |
| | | */ |
| | | public static String firstCharToLowerCase(String str) { |
| | | char firstChar = str.charAt(0); |
| | | if (firstChar >= 'A' && firstChar <= 'Z') { |
| | | char[] arr = str.toCharArray(); |
| | | arr[0] += ('a' - 'A'); |
| | | return new String(arr); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 首字母变大写 |
| | | */ |
| | | public static String firstCharToUpperCase(String str) { |
| | | char firstChar = str.charAt(0); |
| | | if (firstChar >= 'a' && firstChar <= 'z') { |
| | | char[] arr = str.toCharArray(); |
| | | arr[0] -= ('a' - 'A'); |
| | | return new String(arr); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------ Blank |
| | | /** |
| | | * 字符串是否为空白 空白的定义如下: <br> |
| | | * 1、为null <br> |
| | | * 2、为不可见字符(如空格)<br> |
| | | * 3、""<br> |
| | | * |
| | | * @param str 被检测的字符串 |
| | | * @return 是否为空 |
| | | */ |
| | | public static boolean isBlank(String str) { |
| | | int length; |
| | | if ((str == null) || ((length = str.length()) == 0)) { |
| | | return true; |
| | | } |
| | | for (int i = 0; i < length; i++) { |
| | | // 只要有一个非空字符即为非空字符串 |
| | | if (false == Character.isWhitespace(str.charAt(i))) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 字符串是否为非空白 空白的定义如下: <br> |
| | | * 1、不为null <br> |
| | | * 2、不为不可见字符(如空格)<br> |
| | | * 3、不为""<br> |
| | | * |
| | | * @param str 被检测的字符串 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static boolean notBlank(String str) { |
| | | return false == isBlank(str); |
| | | } |
| | | |
| | | /** |
| | | * 是否包含空字符串 |
| | | * |
| | | * @param strs 字符串列表 |
| | | * @return 是否包含空字符串 |
| | | */ |
| | | public static boolean hasBlank(String... strs) { |
| | | if (CollectionKit.isEmpty(strs)) { |
| | | return true; |
| | | } |
| | | for (String str : strs) { |
| | | if (isBlank(str)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 给定所有字符串是否为空白 |
| | | * |
| | | * @param strs 字符串 |
| | | * @return 所有字符串是否为空白 |
| | | */ |
| | | public static boolean isAllBlank(String... strs) { |
| | | if (CollectionKit.isEmpty(strs)) { |
| | | return true; |
| | | } |
| | | for (String str : strs) { |
| | | if (notBlank(str)) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------ Empty |
| | | /** |
| | | * 字符串是否为空,空的定义如下 1、为null <br> |
| | | * 2、为""<br> |
| | | * |
| | | * @param str 被检测的字符串 |
| | | * @return 是否为空 |
| | | */ |
| | | public static boolean isEmpty(String str) { |
| | | return str == null || str.length() == 0; |
| | | } |
| | | |
| | | /** |
| | | * 字符串是否为非空白 空白的定义如下: <br> |
| | | * 1、不为null <br> |
| | | * 2、不为""<br> |
| | | * |
| | | * @param str 被检测的字符串 |
| | | * @return 是否为非空 |
| | | */ |
| | | public static boolean isNotEmpty(String str) { |
| | | return false == isEmpty(str); |
| | | } |
| | | |
| | | /** |
| | | * 当给定字符串为null时,转换为Empty |
| | | * |
| | | * @param str 被转换的字符串 |
| | | * @return 转换后的字符串 |
| | | */ |
| | | public static String nullToEmpty(String str) { |
| | | return nullToDefault(str, EMPTY); |
| | | } |
| | | |
| | | /** |
| | | * 如果字符串是<code>null</code>,则返回指定默认字符串,否则返回字符串本身。 |
| | | * |
| | | * <pre> |
| | | * nullToDefault(null, "default") = "default" |
| | | * nullToDefault("", "default") = "" |
| | | * nullToDefault(" ", "default") = " " |
| | | * nullToDefault("bat", "default") = "bat" |
| | | * </pre> |
| | | * |
| | | * @param str 要转换的字符串 |
| | | * @param defaultStr 默认字符串 |
| | | * |
| | | * @return 字符串本身或指定的默认字符串 |
| | | */ |
| | | public static String nullToDefault(String str, String defaultStr) { |
| | | return (str == null) ? defaultStr : str; |
| | | } |
| | | |
| | | /** |
| | | * 当给定字符串为空字符串时,转换为<code>null</code> |
| | | * |
| | | * @param str 被转换的字符串 |
| | | * @return 转换后的字符串 |
| | | */ |
| | | public static String emptyToNull(String str) { |
| | | return isEmpty(str) ? null : str; |
| | | } |
| | | |
| | | /** |
| | | * 是否包含空字符串 |
| | | * |
| | | * @param strs 字符串列表 |
| | | * @return 是否包含空字符串 |
| | | */ |
| | | public static boolean hasEmpty(String... strs) { |
| | | if (CollectionKit.isEmpty(strs)) { |
| | | return true; |
| | | } |
| | | |
| | | for (String str : strs) { |
| | | if (isEmpty(str)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 是否全部为空字符串 |
| | | * |
| | | * @param strs 字符串列表 |
| | | * @return 是否全部为空字符串 |
| | | */ |
| | | public static boolean isAllEmpty(String... strs) { |
| | | if (CollectionKit.isEmpty(strs)) { |
| | | return true; |
| | | } |
| | | |
| | | for (String str : strs) { |
| | | if (isNotEmpty(str)) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------ Trim |
| | | /** |
| | | * 除去字符串头尾部的空白,如果字符串是<code>null</code>,依然返回<code>null</code>。 |
| | | * |
| | | * <p> |
| | | * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 |
| | | * |
| | | * <pre> |
| | | * trim(null) = null |
| | | * trim("") = "" |
| | | * trim(" ") = "" |
| | | * trim("abc") = "abc" |
| | | * trim(" abc ") = "abc" |
| | | * </pre> |
| | | * |
| | | * </p> |
| | | * |
| | | * @param str 要处理的字符串 |
| | | * |
| | | * @return 除去空白的字符串,如果原字串为<code>null</code>,则返回<code>null</code> |
| | | */ |
| | | public static String trim(String str) { |
| | | return (null == str) ? null : trim(str, 0); |
| | | } |
| | | |
| | | /** |
| | | * 给定字符串数组全部做去首尾空格 |
| | | * |
| | | * @param strs 字符串数组 |
| | | */ |
| | | public static void trim(String[] strs) { |
| | | if (null == strs) { |
| | | return; |
| | | } |
| | | String str; |
| | | for (int i = 0; i < strs.length; i++) { |
| | | str = strs[i]; |
| | | if (null != str) { |
| | | strs[i] = str.trim(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 除去字符串头部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。 |
| | | * |
| | | * <p> |
| | | * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 |
| | | * |
| | | * <pre> |
| | | * trimStart(null) = null |
| | | * trimStart("") = "" |
| | | * trimStart("abc") = "abc" |
| | | * trimStart(" abc") = "abc" |
| | | * trimStart("abc ") = "abc " |
| | | * trimStart(" abc ") = "abc " |
| | | * </pre> |
| | | * |
| | | * </p> |
| | | * |
| | | * @param str 要处理的字符串 |
| | | * |
| | | * @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code> |
| | | */ |
| | | public static String trimStart(String str) { |
| | | return trim(str, -1); |
| | | } |
| | | |
| | | /** |
| | | * 除去字符串尾部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。 |
| | | * |
| | | * <p> |
| | | * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。 |
| | | * |
| | | * <pre> |
| | | * trimEnd(null) = null |
| | | * trimEnd("") = "" |
| | | * trimEnd("abc") = "abc" |
| | | * trimEnd(" abc") = " abc" |
| | | * trimEnd("abc ") = "abc" |
| | | * trimEnd(" abc ") = " abc" |
| | | * </pre> |
| | | * |
| | | * </p> |
| | | * |
| | | * @param str 要处理的字符串 |
| | | * |
| | | * @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code> |
| | | */ |
| | | public static String trimEnd(String str) { |
| | | return trim(str, 1); |
| | | } |
| | | |
| | | /** |
| | | * 除去字符串头尾部的空白符,如果字符串是<code>null</code>,依然返回<code>null</code>。 |
| | | * |
| | | * @param str 要处理的字符串 |
| | | * @param mode <code>-1</code>表示trimStart,<code>0</code>表示trim全部, <code>1</code>表示trimEnd |
| | | * |
| | | * @return 除去指定字符后的的字符串,如果原字串为<code>null</code>,则返回<code>null</code> |
| | | */ |
| | | public static String trim(String str, int mode) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | |
| | | int length = str.length(); |
| | | int start = 0; |
| | | int end = length; |
| | | |
| | | // 扫描字符串头部 |
| | | if (mode <= 0) { |
| | | while ((start < end) && (Character.isWhitespace(str.charAt(start)))) { |
| | | start++; |
| | | } |
| | | } |
| | | |
| | | // 扫描字符串尾部 |
| | | if (mode >= 0) { |
| | | while ((start < end) && (Character.isWhitespace(str.charAt(end - 1)))) { |
| | | end--; |
| | | } |
| | | } |
| | | |
| | | if ((start > 0) || (end < length)) { |
| | | return str.substring(start, end); |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 是否以指定字符串开头 |
| | | * @param str 被监测字符串 |
| | | * @param prefix 开头字符串 |
| | | * @param isIgnoreCase 是否忽略大小写 |
| | | * @return 是否以指定字符串开头 |
| | | */ |
| | | public static boolean startWith(String str, String prefix, boolean isIgnoreCase){ |
| | | if(isIgnoreCase){ |
| | | return str.toLowerCase().startsWith(prefix.toLowerCase()); |
| | | }else{ |
| | | return str.startsWith(prefix); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 是否以指定字符串结尾 |
| | | * @param str 被监测字符串 |
| | | * @param suffix 结尾字符串 |
| | | * @param isIgnoreCase 是否忽略大小写 |
| | | * @return 是否以指定字符串结尾 |
| | | */ |
| | | public static boolean endWith(String str, String suffix, boolean isIgnoreCase){ |
| | | if(isIgnoreCase){ |
| | | return str.toLowerCase().endsWith(suffix.toLowerCase()); |
| | | }else{ |
| | | return str.endsWith(suffix); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 是否包含特定字符,忽略大小写,如果给定两个参数都为<code>null</code>,返回true |
| | | * @param str 被检测字符串 |
| | | * @param testStr 被测试是否包含的字符串 |
| | | * @return 是否包含 |
| | | */ |
| | | public static boolean containsIgnoreCase(String str, String testStr){ |
| | | if(null == str){ |
| | | //如果被监测字符串和 |
| | | return null == testStr; |
| | | } |
| | | return str.toLowerCase().contains(testStr.toLowerCase()); |
| | | } |
| | | |
| | | /** |
| | | * 获得set或get方法对应的标准属性名<br/> |
| | | * 例如:setName 返回 name |
| | | * |
| | | * @param getOrSetMethodName |
| | | * @return 如果是set或get方法名,返回field, 否则null |
| | | */ |
| | | public static String getGeneralField(String getOrSetMethodName) { |
| | | if (getOrSetMethodName.startsWith("get") || getOrSetMethodName.startsWith("set")) { |
| | | return cutPreAndLowerFirst(getOrSetMethodName, 3); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 生成set方法名<br/> |
| | | * 例如:name 返回 setName |
| | | * |
| | | * @param fieldName 属性名 |
| | | * @return setXxx |
| | | */ |
| | | public static String genSetter(String fieldName) { |
| | | return upperFirstAndAddPre(fieldName, "set"); |
| | | } |
| | | |
| | | /** |
| | | * 生成get方法名 |
| | | * |
| | | * @param fieldName 属性名 |
| | | * @return getXxx |
| | | */ |
| | | public static String genGetter(String fieldName) { |
| | | return upperFirstAndAddPre(fieldName, "get"); |
| | | } |
| | | |
| | | /** |
| | | * 去掉首部指定长度的字符串并将剩余字符串首字母小写<br/> |
| | | * 例如:str=setName, preLength=3 -> return name |
| | | * |
| | | * @param str 被处理的字符串 |
| | | * @param preLength 去掉的长度 |
| | | * @return 处理后的字符串,不符合规范返回null |
| | | */ |
| | | public static String cutPreAndLowerFirst(String str, int preLength) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | if (str.length() > preLength) { |
| | | char first = Character.toLowerCase(str.charAt(preLength)); |
| | | if (str.length() > preLength + 1) { |
| | | return first + str.substring(preLength + 1); |
| | | } |
| | | return String.valueOf(first); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 原字符串首字母大写并在其首部添加指定字符串 例如:str=name, preString=get -> return getName |
| | | * |
| | | * @param str 被处理的字符串 |
| | | * @param preString 添加的首部 |
| | | * @return 处理后的字符串 |
| | | */ |
| | | public static String upperFirstAndAddPre(String str, String preString) { |
| | | if (str == null || preString == null) { |
| | | return null; |
| | | } |
| | | return preString + upperFirst(str); |
| | | } |
| | | |
| | | /** |
| | | * 大写首字母<br> |
| | | * 例如:str = name, return Name |
| | | * |
| | | * @param str 字符串 |
| | | * @return 字符串 |
| | | */ |
| | | public static String upperFirst(String str) { |
| | | return Character.toUpperCase(str.charAt(0)) + str.substring(1); |
| | | } |
| | | |
| | | /** |
| | | * 小写首字母<br> |
| | | * 例如:str = Name, return name |
| | | * |
| | | * @param str 字符串 |
| | | * @return 字符串 |
| | | */ |
| | | public static String lowerFirst(String str) { |
| | | if(isBlank(str)){ |
| | | return str; |
| | | } |
| | | return Character.toLowerCase(str.charAt(0)) + str.substring(1); |
| | | } |
| | | |
| | | /** |
| | | * 去掉指定前缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @return 切掉后的字符串,若前缀不是 preffix, 返回原字符串 |
| | | */ |
| | | public static String removePrefix(String str, String prefix) { |
| | | if(isEmpty(str) || isEmpty(prefix)){ |
| | | return str; |
| | | } |
| | | |
| | | if (str.startsWith(prefix)) { |
| | | return str.substring(prefix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 忽略大小写去掉指定前缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串 |
| | | */ |
| | | public static String removePrefixIgnoreCase(String str, String prefix) { |
| | | if(isEmpty(str) || isEmpty(prefix)){ |
| | | return str; |
| | | } |
| | | |
| | | if (str.toLowerCase().startsWith(prefix.toLowerCase())) { |
| | | return str.substring(prefix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 去掉指定后缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param suffix 后缀 |
| | | * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串 |
| | | */ |
| | | public static String removeSuffix(String str, String suffix) { |
| | | if(isEmpty(str) || isEmpty(suffix)){ |
| | | return str; |
| | | } |
| | | |
| | | if (str.endsWith(suffix)) { |
| | | return str.substring(0, str.length() - suffix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 获得字符串对应byte数组 |
| | | * @param str 字符串 |
| | | * @param charset 编码,如果为<code>null</code>使用系统默认编码 |
| | | * @return bytes |
| | | */ |
| | | public static byte[] getBytes(String str, Charset charset){ |
| | | if(null == str){ |
| | | return null; |
| | | } |
| | | return null == charset ? str.getBytes() : str.getBytes(charset); |
| | | } |
| | | |
| | | /** |
| | | * 忽略大小写去掉指定后缀 |
| | | * |
| | | * @param str 字符串 |
| | | * @param suffix 后缀 |
| | | * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串 |
| | | */ |
| | | public static String removeSuffixIgnoreCase(String str, String suffix) { |
| | | if(isEmpty(str) || isEmpty(suffix)){ |
| | | return str; |
| | | } |
| | | |
| | | if (str.toLowerCase().endsWith(suffix.toLowerCase())) { |
| | | return str.substring(0, str.length() - suffix.length()); |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 如果给定字符串不是以prefix开头的,在开头补充 prefix |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @return 补充后的字符串 |
| | | */ |
| | | public static String addPrefixIfNot(String str, String prefix){ |
| | | if(isEmpty(str) || isEmpty(prefix)){ |
| | | return str; |
| | | } |
| | | if(false == str.startsWith(prefix)){ |
| | | str = prefix + str; |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 如果给定字符串不是以suffix结尾的,在尾部补充 suffix |
| | | * @param str 字符串 |
| | | * @param suffix 后缀 |
| | | * @return 补充后的字符串 |
| | | */ |
| | | public static String addSuffixIfNot(String str, String suffix){ |
| | | if(isEmpty(str) || isEmpty(suffix)){ |
| | | return str; |
| | | } |
| | | if(false == str.endsWith(suffix)){ |
| | | str += suffix; |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * 清理空白字符 |
| | | * |
| | | * @param str 被清理的字符串 |
| | | * @return 清理后的字符串 |
| | | */ |
| | | public static String cleanBlank(String str) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | |
| | | return str.replaceAll("\\s*", EMPTY); |
| | | } |
| | | |
| | | /** |
| | | * 切分字符串<br> |
| | | * a#b#c -> [a,b,c] <br> |
| | | * a##b#c -> [a,"",b,c] |
| | | * |
| | | * @param str 被切分的字符串 |
| | | * @param separator 分隔符字符 |
| | | * @return 切分后的集合 |
| | | */ |
| | | public static List<String> split(String str, char separator) { |
| | | return split(str, separator, 0); |
| | | } |
| | | |
| | | /** |
| | | * 切分字符串 |
| | | * |
| | | * @param str 被切分的字符串 |
| | | * @param separator 分隔符字符 |
| | | * @param limit 限制分片数 |
| | | * @return 切分后的集合 |
| | | */ |
| | | public static List<String> split(String str, char separator, int limit) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | List<String> list = new ArrayList<String>(limit == 0 ? 16 : limit); |
| | | if (limit == 1) { |
| | | list.add(str); |
| | | return list; |
| | | } |
| | | |
| | | boolean isNotEnd = true; // 未结束切分的标志 |
| | | int strLen = str.length(); |
| | | StringBuilder sb = new StringBuilder(strLen); |
| | | for (int i = 0; i < strLen; i++) { |
| | | char c = str.charAt(i); |
| | | if (isNotEnd && c == separator) { |
| | | list.add(sb.toString()); |
| | | // 清空StringBuilder |
| | | sb.delete(0, sb.length()); |
| | | |
| | | // 当达到切分上限-1的量时,将所剩字符全部作为最后一个串 |
| | | if (limit != 0 && list.size() == limit - 1) { |
| | | isNotEnd = false; |
| | | } |
| | | } else { |
| | | sb.append(c); |
| | | } |
| | | } |
| | | list.add(sb.toString());// 加入尾串 |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * 切分字符串<br> |
| | | * from jodd |
| | | * |
| | | * @param str 被切分的字符串 |
| | | * @param delimiter 分隔符 |
| | | * @return 字符串 |
| | | */ |
| | | public static String[] split(String str, String delimiter) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | if (str.trim().length() == 0) { |
| | | return new String[] { str }; |
| | | } |
| | | |
| | | int dellen = delimiter.length(); // del length |
| | | int maxparts = (str.length() / dellen) + 2; // one more for the last |
| | | int[] positions = new int[maxparts]; |
| | | |
| | | int i, j = 0; |
| | | int count = 0; |
| | | positions[0] = -dellen; |
| | | while ((i = str.indexOf(delimiter, j)) != -1) { |
| | | count++; |
| | | positions[count] = i; |
| | | j = i + dellen; |
| | | } |
| | | count++; |
| | | positions[count] = str.length(); |
| | | |
| | | String[] result = new String[count]; |
| | | |
| | | for (i = 0; i < count; i++) { |
| | | result[i] = str.substring(positions[i] + dellen, positions[i + 1]); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 改进JDK subString<br> |
| | | * index从0开始计算,最后一个字符为-1<br> |
| | | * 如果from和to位置一样,返回 "" <br> |
| | | * 如果from或to为负数,则按照length从后向前数位置,如果绝对值大于字符串长度,则from归到0,to归到length<br> |
| | | * 如果经过修正的index中from大于to,则互换from和to |
| | | * example: <br> |
| | | * abcdefgh 2 3 -> c <br> |
| | | * abcdefgh 2 -3 -> cde <br> |
| | | * |
| | | * @param string String |
| | | * @param fromIndex 开始的index(包括) |
| | | * @param toIndex 结束的index(不包括) |
| | | * @return 字串 |
| | | */ |
| | | public static String sub(String string, int fromIndex, int toIndex) { |
| | | int len = string.length(); |
| | | if (fromIndex < 0) { |
| | | fromIndex = len + fromIndex; |
| | | if(fromIndex < 0 ) { |
| | | fromIndex = 0; |
| | | } |
| | | } else if(fromIndex >= len) { |
| | | fromIndex = len -1; |
| | | } |
| | | if (toIndex < 0) { |
| | | toIndex = len + toIndex; |
| | | if(toIndex < 0) { |
| | | toIndex = len; |
| | | } |
| | | } else if(toIndex > len) { |
| | | toIndex = len; |
| | | } |
| | | if (toIndex < fromIndex) { |
| | | int tmp = fromIndex; |
| | | fromIndex = toIndex; |
| | | toIndex = tmp; |
| | | } |
| | | if (fromIndex == toIndex) { |
| | | return EMPTY; |
| | | } |
| | | char[] strArray = string.toCharArray(); |
| | | char[] newStrArray = Arrays.copyOfRange(strArray, fromIndex, toIndex); |
| | | return new String(newStrArray); |
| | | } |
| | | |
| | | /** |
| | | * 切割前部分 |
| | | * |
| | | * @param string 字符串 |
| | | * @param toIndex 切割到的位置(不包括) |
| | | * @return 切割后的字符串 |
| | | */ |
| | | public static String subPre(String string, int toIndex) { |
| | | return sub(string, 0, toIndex); |
| | | } |
| | | |
| | | /** |
| | | * 切割后部分 |
| | | * |
| | | * @param string 字符串 |
| | | * @param fromIndex 切割开始的位置(包括) |
| | | * @return 切割后的字符串 |
| | | */ |
| | | public static String subSuf(String string, int fromIndex) { |
| | | if (isEmpty(string)) { |
| | | return null; |
| | | } |
| | | return sub(string, fromIndex, string.length()); |
| | | } |
| | | |
| | | /** |
| | | * 给定字符串是否被字符包围 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @param suffix 后缀 |
| | | * @return 是否包围,空串不包围 |
| | | */ |
| | | public static boolean isSurround(String str, String prefix, String suffix) { |
| | | if (StrKit.isBlank(str)) { |
| | | return false; |
| | | } |
| | | if (str.length() < (prefix.length() + suffix.length())) { |
| | | return false; |
| | | } |
| | | |
| | | return str.startsWith(prefix) && str.endsWith(suffix); |
| | | } |
| | | |
| | | /** |
| | | * 给定字符串是否被字符包围 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @param suffix 后缀 |
| | | * @return 是否包围,空串不包围 |
| | | */ |
| | | public static boolean isSurround(String str, char prefix, char suffix) { |
| | | if (StrKit.isBlank(str)) { |
| | | return false; |
| | | } |
| | | if (str.length() < 2) { |
| | | return false; |
| | | } |
| | | |
| | | return str.charAt(0) == prefix && str.charAt(str.length() - 1) == suffix; |
| | | } |
| | | |
| | | /** |
| | | * 重复某个字符 |
| | | * |
| | | * @param c 被重复的字符 |
| | | * @param count 重复的数目 |
| | | * @return 重复字符字符串 |
| | | */ |
| | | public static String repeat(char c, int count) { |
| | | char[] result = new char[count]; |
| | | for (int i = 0; i < count; i++) { |
| | | result[i] = c; |
| | | } |
| | | return new String(result); |
| | | } |
| | | |
| | | /** |
| | | * 重复某个字符串 |
| | | * |
| | | * @param str 被重复的字符 |
| | | * @param count 重复的数目 |
| | | * @return 重复字符字符串 |
| | | */ |
| | | public static String repeat(String str, int count) { |
| | | |
| | | // 检查 |
| | | final int len = str.length(); |
| | | final long longSize = (long) len * (long) count; |
| | | final int size = (int) longSize; |
| | | if (size != longSize) { |
| | | throw new ArrayIndexOutOfBoundsException("Required String length is too large: " + longSize); |
| | | } |
| | | |
| | | final char[] array = new char[size]; |
| | | str.getChars(0, len, array, 0); |
| | | int n; |
| | | for (n = len; n < size - n; n <<= 1) {// n <<= 1相当于n *2 |
| | | System.arraycopy(array, 0, array, n, n); |
| | | } |
| | | System.arraycopy(array, 0, array, n, size - n); |
| | | return new String(array); |
| | | } |
| | | |
| | | /** |
| | | * 比较两个字符串(大小写敏感)。 |
| | | * |
| | | * <pre> |
| | | * equals(null, null) = true |
| | | * equals(null, "abc") = false |
| | | * equals("abc", null) = false |
| | | * equals("abc", "abc") = true |
| | | * equals("abc", "ABC") = false |
| | | * </pre> |
| | | * |
| | | * @param str1 要比较的字符串1 |
| | | * @param str2 要比较的字符串2 |
| | | * |
| | | * @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code> |
| | | */ |
| | | public static boolean equals(String str1, String str2) { |
| | | if (str1 == null) { |
| | | return str2 == null; |
| | | } |
| | | |
| | | return str1.equals(str2); |
| | | } |
| | | |
| | | /** |
| | | * 比较两个字符串(大小写不敏感)。 |
| | | * |
| | | * <pre> |
| | | * equalsIgnoreCase(null, null) = true |
| | | * equalsIgnoreCase(null, "abc") = false |
| | | * equalsIgnoreCase("abc", null) = false |
| | | * equalsIgnoreCase("abc", "abc") = true |
| | | * equalsIgnoreCase("abc", "ABC") = true |
| | | * </pre> |
| | | * |
| | | * @param str1 要比较的字符串1 |
| | | * @param str2 要比较的字符串2 |
| | | * |
| | | * @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code> |
| | | */ |
| | | public static boolean equalsIgnoreCase(String str1, String str2) { |
| | | if (str1 == null) { |
| | | return str2 == null; |
| | | } |
| | | |
| | | return str1.equalsIgnoreCase(str2); |
| | | } |
| | | |
| | | /** |
| | | * 格式化文本, {} 表示占位符<br> |
| | | * 例如:format("aaa {} ccc", "bbb") ----> aaa bbb ccc |
| | | * |
| | | * @param template 文本模板,被替换的部分用 {} 表示 |
| | | * @param values 参数值 |
| | | * @return 格式化后的文本 |
| | | */ |
| | | public static String format(String template, Object... values) { |
| | | if (CollectionKit.isEmpty(values) || isBlank(template)) { |
| | | return template; |
| | | } |
| | | |
| | | final StringBuilder sb = new StringBuilder(); |
| | | final int length = template.length(); |
| | | |
| | | int valueIndex = 0; |
| | | char currentChar; |
| | | for (int i = 0; i < length; i++) { |
| | | if (valueIndex >= values.length) { |
| | | sb.append(sub(template, i, length)); |
| | | break; |
| | | } |
| | | |
| | | currentChar = template.charAt(i); |
| | | if (currentChar == '{') { |
| | | final char nextChar = template.charAt(++i); |
| | | if (nextChar == '}') { |
| | | sb.append(values[valueIndex++]); |
| | | } else { |
| | | sb.append('{').append(nextChar); |
| | | } |
| | | } else { |
| | | sb.append(currentChar); |
| | | } |
| | | |
| | | } |
| | | |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 格式化文本,使用 {varName} 占位<br> |
| | | * map = {a: "aValue", b: "bValue"} |
| | | * format("{a} and {b}", map) ----> aValue and bValue |
| | | * |
| | | * @param template 文本模板,被替换的部分用 {key} 表示 |
| | | * @param map 参数值对 |
| | | * @return 格式化后的文本 |
| | | */ |
| | | public static String format(String template, Map<?, ?> map) { |
| | | if (null == map || map.isEmpty()) { |
| | | return template; |
| | | } |
| | | |
| | | for (Entry<?, ?> entry : map.entrySet()) { |
| | | template = template.replace("{" + entry.getKey() + "}", entry.getValue().toString()); |
| | | } |
| | | return template; |
| | | } |
| | | |
| | | /** |
| | | * 编码字符串 |
| | | * |
| | | * @param str 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 编码后的字节码 |
| | | */ |
| | | public static byte[] bytes(String str, String charset) { |
| | | return bytes(str, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset)); |
| | | } |
| | | |
| | | /** |
| | | * 编码字符串 |
| | | * |
| | | * @param str 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 编码后的字节码 |
| | | */ |
| | | public static byte[] bytes(String str, Charset charset) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | |
| | | if (null == charset) { |
| | | return str.getBytes(); |
| | | } |
| | | return str.getBytes(charset); |
| | | } |
| | | |
| | | /** |
| | | * 将byte数组转为字符串 |
| | | * |
| | | * @param bytes byte数组 |
| | | * @param charset 字符集 |
| | | * @return 字符串 |
| | | */ |
| | | public static String str(byte[] bytes, String charset) { |
| | | return str(bytes, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset)); |
| | | } |
| | | |
| | | /** |
| | | * 解码字节码 |
| | | * |
| | | * @param data 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 解码后的字符串 |
| | | */ |
| | | public static String str(byte[] data, Charset charset) { |
| | | if (data == null) { |
| | | return null; |
| | | } |
| | | |
| | | if (null == charset) { |
| | | return new String(data); |
| | | } |
| | | return new String(data, charset); |
| | | } |
| | | |
| | | /** |
| | | * 将编码的byteBuffer数据转换为字符串 |
| | | * @param data 数据 |
| | | * @param charset 字符集,如果为空使用当前系统字符集 |
| | | * @return 字符串 |
| | | */ |
| | | public static String str(ByteBuffer data, String charset){ |
| | | if(data == null) { |
| | | return null; |
| | | } |
| | | |
| | | return str(data, Charset.forName(charset)); |
| | | } |
| | | |
| | | /** |
| | | * 将编码的byteBuffer数据转换为字符串 |
| | | * @param data 数据 |
| | | * @param charset 字符集,如果为空使用当前系统字符集 |
| | | * @return 字符串 |
| | | */ |
| | | public static String str(ByteBuffer data, Charset charset){ |
| | | if(null == charset) { |
| | | charset = Charset.defaultCharset(); |
| | | } |
| | | return charset.decode(data).toString(); |
| | | } |
| | | |
| | | /** |
| | | * 字符串转换为byteBuffer |
| | | * @param str 字符串 |
| | | * @param charset 编码 |
| | | * @return byteBuffer |
| | | */ |
| | | public static ByteBuffer byteBuffer(String str, String charset) { |
| | | return ByteBuffer.wrap(StrKit.bytes(str, charset)); |
| | | } |
| | | |
| | | /** |
| | | * 以 conjunction 为分隔符将多个对象转换为字符串 |
| | | * |
| | | * @param conjunction 分隔符 |
| | | * @param objs 数组 |
| | | * @return 连接后的字符串 |
| | | */ |
| | | public static String join(String conjunction, Object... objs) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | boolean isFirst = true; |
| | | for (Object item : objs) { |
| | | if (isFirst) { |
| | | isFirst = false; |
| | | } else { |
| | | sb.append(conjunction); |
| | | } |
| | | sb.append(item); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。</br> |
| | | * 例如:HelloWorld->hello_world |
| | | * |
| | | * @param camelCaseStr 转换前的驼峰式命名的字符串 |
| | | * @return 转换后下划线大写方式命名的字符串 |
| | | */ |
| | | public static String toUnderlineCase(String camelCaseStr) { |
| | | if (camelCaseStr == null) { |
| | | return null; |
| | | } |
| | | |
| | | final int length = camelCaseStr.length(); |
| | | StringBuilder sb = new StringBuilder(); |
| | | char c; |
| | | boolean isPreUpperCase = false; |
| | | for (int i = 0; i < length; i++) { |
| | | c = camelCaseStr.charAt(i); |
| | | boolean isNextUpperCase = true; |
| | | if (i < (length - 1)) { |
| | | isNextUpperCase = Character.isUpperCase(camelCaseStr.charAt(i + 1)); |
| | | } |
| | | if (Character.isUpperCase(c)) { |
| | | if (!isPreUpperCase || !isNextUpperCase) { |
| | | if (i > 0) sb.append(UNDERLINE); |
| | | } |
| | | isPreUpperCase = true; |
| | | } else { |
| | | isPreUpperCase = false; |
| | | } |
| | | sb.append(Character.toLowerCase(c)); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br> |
| | | * 例如:hello_world->HelloWorld |
| | | * |
| | | * @param name 转换前的下划线大写方式命名的字符串 |
| | | * @return 转换后的驼峰式命名的字符串 |
| | | */ |
| | | public static String toCamelCase(String name) { |
| | | if (name == null) { |
| | | return null; |
| | | } |
| | | if (name.contains(UNDERLINE)) { |
| | | name = name.toLowerCase(); |
| | | |
| | | StringBuilder sb = new StringBuilder(name.length()); |
| | | boolean upperCase = false; |
| | | for (int i = 0; i < name.length(); i++) { |
| | | char c = name.charAt(i); |
| | | |
| | | if (c == '_') { |
| | | upperCase = true; |
| | | } else if (upperCase) { |
| | | sb.append(Character.toUpperCase(c)); |
| | | upperCase = false; |
| | | } else { |
| | | sb.append(c); |
| | | } |
| | | } |
| | | return sb.toString(); |
| | | } else |
| | | return name; |
| | | } |
| | | |
| | | /** |
| | | * 包装指定字符串 |
| | | * |
| | | * @param str 被包装的字符串 |
| | | * @param prefix 前缀 |
| | | * @param suffix 后缀 |
| | | * @return 包装后的字符串 |
| | | */ |
| | | public static String wrap(String str, String prefix, String suffix) { |
| | | return format("{}{}{}", prefix, str, suffix); |
| | | } |
| | | |
| | | /** |
| | | * 指定字符串是否被包装 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefix 前缀 |
| | | * @param suffix 后缀 |
| | | * @return 是否被包装 |
| | | */ |
| | | public static boolean isWrap(String str, String prefix, String suffix) { |
| | | return str.startsWith(prefix) && str.endsWith(suffix); |
| | | } |
| | | |
| | | /** |
| | | * 指定字符串是否被同一字符包装(前后都有这些字符串) |
| | | * |
| | | * @param str 字符串 |
| | | * @param wrapper 包装字符串 |
| | | * @return 是否被包装 |
| | | */ |
| | | public static boolean isWrap(String str, String wrapper) { |
| | | return isWrap(str, wrapper, wrapper); |
| | | } |
| | | |
| | | /** |
| | | * 指定字符串是否被同一字符包装(前后都有这些字符串) |
| | | * |
| | | * @param str 字符串 |
| | | * @param wrapper 包装字符 |
| | | * @return 是否被包装 |
| | | */ |
| | | public static boolean isWrap(String str, char wrapper) { |
| | | return isWrap(str, wrapper, wrapper); |
| | | } |
| | | |
| | | /** |
| | | * 指定字符串是否被包装 |
| | | * |
| | | * @param str 字符串 |
| | | * @param prefixChar 前缀 |
| | | * @param suffixChar 后缀 |
| | | * @return 是否被包装 |
| | | */ |
| | | public static boolean isWrap(String str, char prefixChar, char suffixChar) { |
| | | return str.charAt(0) == prefixChar && str.charAt(str.length() - 1) == suffixChar; |
| | | } |
| | | |
| | | /** |
| | | * 补充字符串以满足最小长度 StrUtil.padPre("1", 3, '0');//"001" |
| | | * |
| | | * @param str 字符串 |
| | | * @param minLength 最小长度 |
| | | * @param padChar 补充的字符 |
| | | * @return 补充后的字符串 |
| | | */ |
| | | public static String padPre(String str, int minLength, char padChar) { |
| | | if (str.length() >= minLength) { |
| | | return str; |
| | | } |
| | | StringBuilder sb = new StringBuilder(minLength); |
| | | for (int i = str.length(); i < minLength; i++) { |
| | | sb.append(padChar); |
| | | } |
| | | sb.append(str); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 补充字符串以满足最小长度 StrUtil.padEnd("1", 3, '0');//"100" |
| | | * |
| | | * @param str 字符串 |
| | | * @param minLength 最小长度 |
| | | * @param padChar 补充的字符 |
| | | * @return 补充后的字符串 |
| | | */ |
| | | public static String padEnd(String str, int minLength, char padChar) { |
| | | if (str.length() >= minLength) { |
| | | return str; |
| | | } |
| | | StringBuilder sb = new StringBuilder(minLength); |
| | | sb.append(str); |
| | | for (int i = str.length(); i < minLength; i++) { |
| | | sb.append(padChar); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 创建StringBuilder对象 |
| | | * |
| | | * @return StringBuilder对象 |
| | | */ |
| | | public static StringBuilder builder() { |
| | | return new StringBuilder(); |
| | | } |
| | | |
| | | /** |
| | | * 创建StringBuilder对象 |
| | | * |
| | | * @return StringBuilder对象 |
| | | */ |
| | | public static StringBuilder builder(int capacity) { |
| | | return new StringBuilder(capacity); |
| | | } |
| | | |
| | | /** |
| | | * 创建StringBuilder对象 |
| | | * |
| | | * @return StringBuilder对象 |
| | | */ |
| | | public static StringBuilder builder(String... strs) { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | for (String str : strs) { |
| | | sb.append(str); |
| | | } |
| | | return sb; |
| | | } |
| | | |
| | | /** |
| | | * 获得StringReader |
| | | * |
| | | * @param str 字符串 |
| | | * @return StringReader |
| | | */ |
| | | public static StringReader getReader(String str) { |
| | | return new StringReader(str); |
| | | } |
| | | |
| | | /** |
| | | * 获得StringWriter |
| | | * |
| | | * @return StringWriter |
| | | */ |
| | | public static StringWriter getWriter() { |
| | | return new StringWriter(); |
| | | } |
| | | |
| | | /** |
| | | * 编码字符串 |
| | | * |
| | | * @param str 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 编码后的字节码 |
| | | */ |
| | | public static byte[] encode(String str, String charset) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | |
| | | if(isBlank(charset)) { |
| | | return str.getBytes(); |
| | | } |
| | | try { |
| | | return str.getBytes(charset); |
| | | } catch (UnsupportedEncodingException e) { |
| | | throw new RuntimeException(format("Charset [{}] unsupported!", charset)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 解码字节码 |
| | | * |
| | | * @param data 字符串 |
| | | * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
| | | * @return 解码后的字符串 |
| | | */ |
| | | public static String decode(byte[] data, String charset) { |
| | | if (data == null) { |
| | | return null; |
| | | } |
| | | |
| | | if(isBlank(charset)) { |
| | | return new String(data); |
| | | } |
| | | try { |
| | | return new String(data, charset); |
| | | } catch (UnsupportedEncodingException e) { |
| | | throw new RuntimeException(format("Charset [{}] unsupported!", charset)); |
| | | } |
| | | } |
| | | } |
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/WafKit.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/WafRequestWrapper.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/exception/ToolBoxException.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/Convert.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/DateUtil.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/FileUtil.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/HttpSessionHolder.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/IdGenerator.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/MD5Util.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/NumUtil.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/PingYinUtil.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/RenderUtil.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/ResKit.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SimpleContrast.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SpringContextHolder.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SqlUtil.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/ToolUtil.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/xss/XssFilter.java
DriverOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/xss/XssHttpServletRequestWrapper.java
DriverOKTravel/guns-core/src/main/resources/META-INF/spring.factories
DriverOKTravel/guns-core/src/main/resources/default-config.properties
DriverOKTravel/guns-generator/pom.xml
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/GunsCodeGenerator.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/AbstractGeneratorConfig.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/GunsGeneratorConfig.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/WebGeneratorConfig.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/model/GenQo.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/SimpleTemplateEngine.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/base/AbstractTemplateEngine.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/base/GunsTemplateEngine.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ContextConfig.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ControllerConfig.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/DaoConfig.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/Menu.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/PageConfig.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ServiceConfig.java
DriverOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/SqlConfig.java
DriverOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/Controller.java.btl
DriverOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/menu_sql.sql.btl
DriverOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page.html.btl
DriverOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page.js.btl
DriverOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_add.html.btl
DriverOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_edit.html.btl
DriverOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_info.js.btl
DriverOKTravel/pom.xml
ManagementOKTravel/.gitattributes
ManagementOKTravel/.gitignore
ManagementOKTravel/LICENSE
ManagementOKTravel/README.md
ManagementOKTravel/guns-core/pom.xml
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/CoreFlag.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/aop/BaseControllerExceptionHandler.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/controller/BaseController.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/controller/GlobalController.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/controller/GunsErrorView.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/tips/ErrorTip.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/tips/SuccessTip.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/tips/Tip.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/warpper/BaseControllerWarpper.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/BaseCacheFactory.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/CacheKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/EhcacheFactory.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/ICache.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/ILoader.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/DefaultFastjsonConfig.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/DefaultMultiConfig.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/DefaultProperties.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/DefaultWebConfig.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/properties/DruidProperties.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/properties/MutiDataSourceProperties.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/constant/IsMenu.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/datascope/DataScope.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/datascope/DataScopeInterceptor.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/db/Db.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/exception/GunsException.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/exception/GunsExceptionEnum.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/exception/ServiceExceptionEnum.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/mutidatasource/DataSourceContextHolder.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/mutidatasource/DynamicDataSource.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/mutidatasource/annotion/DataSource.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/mutidatasource/aop/MultiSourceExAop.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/node/MenuNode.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/node/ZTreeNode.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/page/PageBT.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/page/PageInfoBT.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/qr/ImgQrTool.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/qr/MatrixToImageConfig.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/qr/MatrixToImageWriter.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/qr/QrImage.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/BasicType.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/BeanKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/ClassKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/CollectionKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/DateTime.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/DateTimeKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/HexKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/HttpKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/ObjectKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/PageKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/StrKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/WafKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/WafRequestWrapper.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/exception/ToolBoxException.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/Convert.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/DateUtil.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/ExcelExportUtil.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/FileUtil.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/HttpSessionHolder.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/IdGenerator.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/MD5Util.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/NumUtil.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/PingYinUtil.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/RenderUtil.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/ResKit.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SimpleContrast.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SpringContextHolder.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SqlUtil.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/ToolUtil.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/xss/XssFilter.java
ManagementOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/xss/XssHttpServletRequestWrapper.java
ManagementOKTravel/guns-core/src/main/resources/META-INF/spring.factories
ManagementOKTravel/guns-core/src/main/resources/default-config.properties
ManagementOKTravel/guns-generator/pom.xml
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/GunsCodeGenerator.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/AbstractGeneratorConfig.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/GunsGeneratorConfig.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/WebGeneratorConfig.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/model/GenQo.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/SimpleTemplateEngine.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/base/AbstractTemplateEngine.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/base/GunsTemplateEngine.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ContextConfig.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ControllerConfig.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/DaoConfig.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/Menu.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/PageConfig.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ServiceConfig.java
ManagementOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/SqlConfig.java
ManagementOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/Controller.java.btl
ManagementOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/menu_sql.sql.btl
ManagementOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page.html.btl
ManagementOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page.js.btl
ManagementOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_add.html.btl
ManagementOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_edit.html.btl
ManagementOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_info.js.btl
ManagementOKTravel/pom.xml
UserOKTravel/.gitattributes
UserOKTravel/.gitignore
UserOKTravel/README.md
UserOKTravel/guns-core/pom.xml
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/CoreFlag.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/aop/BaseControllerExceptionHandler.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/controller/BaseController.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/controller/GlobalController.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/controller/GunsErrorView.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/tips/ErrorTip.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/tips/SuccessTip.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/tips/Tip.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/base/warpper/BaseControllerWarpper.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/BaseCacheFactory.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/CacheKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/EhcacheFactory.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/ICache.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/cache/ILoader.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/DefaultFastjsonConfig.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/DefaultMultiConfig.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/DefaultProperties.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/DefaultWebConfig.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/properties/DruidProperties.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/config/properties/MutiDataSourceProperties.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/constant/IsMenu.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/datascope/DataScope.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/datascope/DataScopeInterceptor.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/db/Db.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/exception/GunsException.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/exception/GunsExceptionEnum.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/exception/ServiceExceptionEnum.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/mutidatasource/DataSourceContextHolder.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/mutidatasource/DynamicDataSource.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/mutidatasource/annotion/DataSource.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/mutidatasource/aop/MultiSourceExAop.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/node/MenuNode.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/node/ZTreeNode.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/page/PageBT.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/page/PageInfoBT.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/qr/ImgQrTool.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/qr/MatrixToImageConfig.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/qr/MatrixToImageWriter.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/qr/QrImage.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/BasicType.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/BeanKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/ClassKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/CollectionKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/DateTime.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/DateTimeKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/HexKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/HttpKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/ObjectKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/PageKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/StrKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/WafKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/WafRequestWrapper.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/support/exception/ToolBoxException.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/Convert.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/DateUtil.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/ExcelExportUtil.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/FileUtil.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/HttpSessionHolder.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/IdGenerator.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/MD5Util.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/NumUtil.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/PingYinUtil.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/RenderUtil.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/ResKit.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SimpleContrast.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SpringContextHolder.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/SqlUtil.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/ToolUtil.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/xss/XssFilter.java
UserOKTravel/guns-core/src/main/java/com/stylefeng/guns/core/xss/XssHttpServletRequestWrapper.java
UserOKTravel/guns-core/src/main/resources/META-INF/spring.factories
UserOKTravel/guns-core/src/main/resources/default-config.properties
UserOKTravel/guns-generator/pom.xml
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/GunsCodeGenerator.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/AbstractGeneratorConfig.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/GunsGeneratorConfig.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/config/WebGeneratorConfig.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/action/model/GenQo.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/SimpleTemplateEngine.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/base/AbstractTemplateEngine.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/base/GunsTemplateEngine.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ContextConfig.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ControllerConfig.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/DaoConfig.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/Menu.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/PageConfig.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/ServiceConfig.java
UserOKTravel/guns-generator/src/main/java/com/stylefeng/guns/generator/engine/config/SqlConfig.java
UserOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/Controller.java.btl
UserOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/menu_sql.sql.btl
UserOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page.html.btl
UserOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page.js.btl
UserOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_add.html.btl
UserOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_edit.html.btl
UserOKTravel/guns-generator/src/main/resources/gunsTemplate/advanced/page_info.js.btl
UserOKTravel/pom.xml |