还没有恢复,我先把友链删掉了。
名称:ZY知识库简介:这是一个用于分享知识和经验的平台网址:https://pljzy.top大佬,交换友链,已添加贵站
很好奇,如果按文章说的,2核,cpu100%计算时间10ms,等待时间100ms,需要线程:2 x 1 x (1 + 100/10) = 22计算时间5ms,等待时间 500ms需要线程:2 x 1 x (1 + 500/5) = 200计算时间1ms,等待时间 1000ms需要线程:2 x 1 x (1 + 1000/1) = 2000这样真的合理吗?期待博主回复
有没有Rocky linux的dd脚本?
谢谢
感谢楼主!已测试可以使用!
我也是
请教大佬,eladmin的踢出用户功能是怎么实现的?我看后端只是删除了redis里存的用户, 被踢的那个用户前端是怎么知道该跳转页面的?
拿走了了
首页
统计
微语
留言
邻居
壁纸
推荐
我的开源
Search
1
快速解决 npm 安装 node-sass 速度慢/错误的问题
20,331 阅读
2
升级 element-ui 2.15.7 后遇到 el-date-picker 警告问题
9,486 阅读
3
前端 axios 中 qs 介绍与使用
7,887 阅读
4
Spring boot 整合 FreeMarker 实现代码生成功能
7,288 阅读
5
EL-ADMIN V2.5 版本发布,新增多项实用功能,代码多项优化
6,451 阅读
推荐分享
文章推荐
资源分享
软件开发
异常记录
Linux学习
日常杂记
开源
登录
Search
标签搜索
Java记录
Linux系统
eladmin开源
Web前端
Spring教程
Docker容器
其他
Git教程
Google插件
jpa
好文分享
Nginx配置
异常记录
持续集成工具
数据库
线程池
Typecho博客
Azure管理
Lambda表达式
PowerDesigner
知了小站
不怕学问浅,就怕志气短。
累计撰写
72
篇文章
累计收到
373
条评论
首页
栏目
推荐分享
文章推荐
资源分享
软件开发
异常记录
Linux学习
日常杂记
开源
页面
统计
微语
留言
邻居
壁纸
推荐
我的开源
用户登录
登录
搜索到
21
篇与
的结果
2021-02-13
@Autowire 和 @Resource 注解的区别与使用的正确姿势
今天使用Idea写代码的时候,看到之前的项目中显示有warning的提示,去看了下,是如下代码?@Autowire private JdbcTemplate jdbcTemplate;提示的警告信息Field injection is not recommended Inspection info: Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies". 这段是Spring工作组的建议,大致翻译一下: 属性字段注入的方式不推荐,检查到的问题是:Spring团队建议:"始终在bean中使用基于构造函数的依赖项注入, 始终对强制性依赖项使用断言如图:Field注入警告注入方式虽然当前有关Spring Framework(5.0.3)的文档仅定义了两种主要的注入类型,但实际上有三种:基于构造函数的依赖注入public class UserServiceImpl implents UserService{ private UserDao userDao; @Autowire public UserServiceImpl(UserDao userDao){ this.userDao = userDao; } }基于Setter的依赖注入public class UserServiceImpl implents UserService{ private UserDao userDao; @Autowire public serUserDao(UserDao userDao){ this.userDao = userDao; } }基于字段的依赖注入public class UserServiceImpl implents UserService{ @Autowire private UserDao userDao; }基于字段的依赖注入方式会在Idea当中吃到黄牌警告,但是这种使用方式使用的也最广泛,因为简洁方便.您甚至可以在一些Spring指南中看到这种注入方法,尽管在文档中不建议这样做.(有点执法犯法的感觉)如图基于字段的依赖注入缺点1、对于有final修饰的变量不好使Spring的IOC对待属性的注入使用的是set形式,但是final类型的变量在调用class的构造函数的这个过程当中就得初始化完成,这个是基于字段的依赖注入做不到的地方.只能使用基于构造函数的依赖注入的方式2、掩盖单一职责的设计思想我们都知道在OOP的设计当中有一个单一职责思想,如果你采用的是基于构造函数的依赖注入的方式来使用Spring的IOC的时候,当你注入的太多的时候,这个构造方法的参数就会很庞大,类似于下面.当你看到这个类的构造方法那么多参数的时候,你自然而然的会想一下:这个类是不是违反了单一职责思想?.但是使用基于字段的依赖注入不会让你察觉,你会很沉浸在@Autowire当中public class VerifyServiceImpl implents VerifyService{ private AccountService accountService; private UserService userService; private IDService idService; private RoleService roleService; private PermissionService permissionService; private EnterpriseService enterpriseService; private EmployeeService employService; private TaskService taskService; private RedisService redisService; private MQService mqService; public SystemLogDto(AccountService accountService, UserService userService, IDService idService, RoleService roleService, PermissionService permissionService, EnterpriseService enterpriseService, EmployeeService employService, TaskService taskService, RedisService redisService, MQService mqService) { this.accountService = accountService; this.userService = userService; this.idService = idService; this.roleService = roleService; this.permissionService = permissionService; this.enterpriseService = enterpriseService; this.employService = employService; this.taskService = taskService; this.redisService = redisService; this.mqService = mqService; } }3、与Spring的IOC机制紧密耦合当你使用基于字段的依赖注入方式的时候,确实可以省略构造方法和setter这些个模板类型的方法,但是,你把控制权全给Spring的IOC了,别的类想重新设置下你的某个注入属性,没法处理(当然反射可以做到).本身Spring的目的就是解藕和依赖反转,结果通过再次与类注入器(在本例中为Spring)耦合,失去了通过自动装配类字段而实现的对类的解耦,从而使类在Spring容器之外无效.4、隐藏依赖性当你使用Spring的IOC的时候,被注入的类应当使用一些public类型(构造方法,和setter类型方法)的方法来向外界表达:我需要什么依赖.但是基于字段的依赖注入的方式,基本都是private形式的,private把属性都给封印到class当中了.5、无法对注入的属性进行安检基于字段的依赖注入方式,你在程序启动的时候无法拿到这个类,只有在真正的业务使用的时候才会拿到,一般情况下,这个注入的都是非null的,万一要是null怎么办,在业务处理的时候错误才爆出来,时间有点晚了,如果在启动的时候就暴露出来,那么bug就可以很快得到修复(当然你可以加注解校验).如果你想在属性注入的时候,想根据这个注入的对象操作点东西,你无法办到.我碰到过的例子:一些配置信息啊,有些人总是会配错误,等到了自己测试业务阶段才知道配错了,例如线程初始个数不小心配置成了3000,机器真的是狂叫啊!这个时候就需要再某些Value注入的时候做一个检测机制.结论通过上面,我们可以看到,基于字段的依赖注入方式有很多缺点,我们应当避免使用基于字段的依赖注入.推荐的方法是使用基于构造函数和基于setter的依赖注入.对于必需的依赖项,建议使用基于构造函数的注入,以使它们成为不可变的,并防止它们为null。对于可选的依赖项,建议使用基于Setter的注入后记翻译自 field-injection-is-not-recommended,加入了自己的白话理解!原文链接:https://juejin.cn/post/6844904064212271117
2021年02月13日
1,137 阅读
0 评论
2 点赞
2021-02-08
EL-ADMIN 邮箱配置之使用 QQ 邮箱发送邮件
EL-ADMIN 配置邮箱后,发送邮件提示:邮箱发送邮件失败:AuthenticationFailedExceptionissues 地址:https://github.com/elunez/eladmin/issues/571修复步骤1、在QQ邮箱中 开启 IMAP/SMTP服务,获取独立密码2、在邮件工具里面配置邮箱信息参数说明1、发件人用户名:用户收信时显示的发件人名称2、邮箱密码:QQ邮箱需要为SMTP服务单独设置密码3、QQ 邮箱的 SMTP 地址:smtp.qq.com4、SMTP 使用默认的 465 即可修改代码定位到:eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java修改第 72 行// 设置用户 String user = emailConfig.getFromUser().split("@")[0]; account.setUser(user);重新启动项目即可
2021年02月08日
1,160 阅读
0 评论
3 点赞
2020-08-24
Typecho 迁移到 Docker 的过程记录
前言之前博客搭建在阿里云的机器上,现在快过期了,加上原机器带宽太小,就不打算续费了,现在就需要将 Typecho 博客迁移到新机器上。以前使用的是宝塔面板搭建的,现在不想把机器环境搞得乱七八糟,因此选择使用 Docker 来搭建 Typecho。安装Docker使用一键脚本安装Dockercurl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun && systemctl start docker && systemctl enable docker如果提示 curl 命令不存在,就需要先安装 curl# Centos yum -y install curl # Ubuntu、Debian apt -y install curl配置镜像加速如果你机器是国内的机器,那么需要配置镜像加速阿里云镜像获取地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors修改 /etc/docker/daemon.json,文件不存在就创建一个{ "registry-mirrors": [ "你的加速地址" ] }安装数据库这里选择的是 Mariadb,可自行选择数据库镜像,这里配置参数就不做解释了,懂的都懂docker run -d -v /home/mysql:/var/lib/mysql \ -p 3306:3306 -e MYSQL_ROOT_PASSWORD=密码 \ --privileged=true --restart=always --name mariadb mariadb安装 PHP安装官方的 php:7.2-fpm 镜像后,还需要进入容器安装 mysql pdo 才能使用 Mysql 数据库,比较麻烦,这里我自己在 php:7.2-fpm 的基础上构建了个带 mysql pdo 的镜像,可以选择性使用。docker run -d -v /home/nginx/html:/var/www/html \ -p 8080:8080 --link mariadb:mariadb --name php dqjdda/php安装 Nginxdocker run -d \ --link php:php \ --name nginx --restart always \ -p 80:80 -p 443:443 \ -e "TZ=Asia/Shanghai" \ -v /home/nginx/nginx.conf:/etc/nginx/nginx.conf \ -v /home/nginx/conf.d:/etc/nginx/conf.d \ -v /home/nginx/logs:/var/log/nginx \ -v /home/nginx/cert:/etc/nginx/cert \ -v /home/nginx/html:/var/www/html \ nginx配置 Nginx/home/nginx/conf.d 用于放配置文件/home/nginx/logs 存放日志/home/nginx/cert 存放证书/home/nginx/html 存放网页在 /home/nginx/conf.d 目录创建文件 blog.confserver { listen 443 ssl http2; server_name www.ydyno.com; gzip on; # 缓存SSL ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; # 证书配置 ssl_certificate /etc/nginx/cert/ydyno.com/ydyno.com_chain.crt; ssl_certificate_key /etc/nginx/cert/ydyno.com/ydyno.com_key.key; root /var/www/html/ydyno; index index.php; # 伪静态 if (!-e $request_filename) { rewrite ^(.*)$ /index.php$1 last; } location ~ .*\.php(\/.*)*$ { include fastcgi_params; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; fastcgi_pass php:9000; } location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ { expires 5d; } # deny access to . files, for security location ~ /\. { log_not_found off; deny all; } } server { listen 80; server_name www.ydyno.com ydyno.com; return 301 https://www.ydyno.com$request_uri; }迁移博客直接将老服务器的博客目录移动到 /var/www/html/ydyno ,然后将数据库导出,然后导入到新库即可
2020年08月24日
2,380 阅读
7 评论
2 点赞
2020-02-20
快速解决 npm 安装 node-sass 速度慢/错误的问题
可通过配置淘宝的镜像源解决,首先配置淘宝的镜像源npm config set registry https://registry.npm.taobao.org然后在 ~/.npmrc 加入下面内容sass_binary_site=https://npm.taobao.org/mirrors/node-sass/.npmrc 文件位于win:C:\Users\[你的账户名称]\.npmrc linux:直接使用 vi ~/.npmrc完整配置如图
2020年02月20日
20,331 阅读
3 评论
16 点赞
2019-12-30
前端 axios 中 qs 介绍与使用
首先 qs 是一个 npm 仓库所管理的包,可通过 npm install qs 命令进行安装地址: https://www.npmjs.com/package/qsqs.parse()qs.parse() 将URL解析成对象的形式const Qs = require('qs'); let url = 'method=query_sql_dataset_data&projectId=85&appToken=7d22e38e-5717-11e7-907b-a6006ad3dba0'; Qs.parse(url); console.log(Qs.parse(url));qs.stringify()qs.stringify() 将对象序列化成URL的形式,以&进行拼接const Qs = require('qs'); let obj= { method: "query_sql_dataset_data", projectId: "85", appToken: "7d22e38e-5717-11e7-907b-a6006ad3dba0", datasetId: " 12564701" }; Qs.stringify(obj); console.log(Qs.stringify(obj));那么当我们需要传递数组的时候,我们就可以通过下面方式进行处理:默认情况下,它们给出明确的索引,如下代码:qs.stringify({ a: ['b', 'c', 'd'] }); // 'a[0]=b&a[1]=c&a[2]=d'也可以进行重写这种默认方式为falseqs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }); // 'a=b&a=c&a=d'当然,也可以通过arrayFormat 选项进行格式化输出,如下代码所示:qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }) // 'a[0]=b&a[1]=c' qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }) // 'a[]=b&a[]=c' qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }) // 'a=b&a=c'在这里需要注意的是,JSON中同样存在stringify方法,但是两者之间的区别是很明显的,如下所示:{"uid":"cs11","pwd":"000000als","username":"cs11","password":"000000als"} uid=cs11&pwd=000000als&username=cs11&password=000000als如上所示,前者是采用 JSON.stringify(param) 进行处理,后者是采用 Qs.stringify(param) 进行处理的。对于JSON.stringify和JSON的使用可参见https://blog.csdn.net/suwu150/article/details/76100120原文地址:https://www.jianshu.com/p/67223e177aa6
2019年12月30日
7,887 阅读
2 评论
7 点赞
2019-12-27
解决 Vue 在 History 模式部署在 Nginx 上刷新报 404 的问题
教程适用于history模式,假设域名假设为:auauz.net原配置server { listen 80; server_name auauz.net; root /www/wwwroot/eladmin-web/dist; index index.html; error_page 404 /index.html; }修改如下server { listen 80; server_name auauz.net; location / { root /www/wwwroot/eladmin-web/dist; try_files $uri $uri/ @router; index index.html; } location @router { rewrite ^.*$ /index.html last; } }
2019年12月27日
3,577 阅读
6 评论
0 点赞
2019-12-19
ES6 语法大全 export,import,for.of循环,promise等等
变量let 局部变量 const 常量 var 全局变量字符串的拓展let str = "123" str.includes("1")//true includes方法 是否包含 str.startsWith("2")//false 是否以2开头 str.endsWith("2")//false 是否以2结尾解构表达式//数组解构 let arr = [1,2,3] const [x,y,z] = arr;// x,y,z对应 1,2,3 //对象解构 const person = { name:"jack", age:21, language:['java','php'], } let {name,age,language} = person //自定义命名 let {name:n,age:a,language} = person 函数的优化//参数上面的优化=1,指当b没有值时默认为1 function test(a,b=1){ console.log(a+b) }箭头函数//Demo1 单个参数 var demo1= fucntion demo1(obj){ console.log(obj) } 箭头函数简化为: var demo1= obj =>console.log(obj); //Demo2 两个参数 var sum =function(a,b){ console.log(a+n) } 箭头函数简化为: var sum = (a,b)=>console.log(obj); //Demo3 没有参数 let sayHello = ()=>console.log("hello!"); //Demo4 代码不止一行 使用 {} var sum = (a,b)=>{ console.log(a+n); console.log(a+n) } //Demo5 对象的函数简写 let person ={ name:“jeck”; //原来 eat:function(food){ console.log(this.name +food) } //箭头函数 eat2:food=>console.log(this.name +food) //简写版 eat3(food){ console.log(this.name +food) } } //Demo6:箭头函数配合解构表达式 let person ={ name:“jeck”; eat2:food=>console.log(this.name +food) } function test1(person){ console.log(person.name); } //简化调用函数 使用{}传参数,传入对象 var test1=({name})=>console.log(name); test1(person );map和reduce函数map 让原来的集合经过 map 中的函数 进行处理回调let arr = ['1','2','3']; arr.map(s=>parseInt(s))//字符串转化为内证书 //reduce() 接收一个函数和一个初始值 第一个参数时上一次reduce的处理结果 第二个参数是数组中要处理的下一个元素 const arr = [1,20,30,40] arr.reduce((a,b)=>a+b)拓展运算符(三个点…)将一个数组转为用逗号分隔的参数序列function add(a,b){ return a+b; } var number = [1,2]; //数组合并 var arrs=[...[1,2,3],...[4,5,6]];//[1,2,3,4,5,6] //将字符串转为数组 console.log([...'hello'])//['h','e','l','l','o']promise// 函数格式 const promise = new promise(function(resolve,reject){ //操作 //if(success){ resolve(value);//成功 }else{ reject(error)//失败 } }) //执行完了在执行一些东西的话 promise.then(function(value){ //异步回调 }).catch(function(error){ //异常回调 })set和mapset 只能保存不同元素,相同的元素会被忽略let set = new set(); let set = new set([2,3,4,5]); //map接受一个数组,数组中的元素时键值对 let map = new map([ ['key','value'], ['key1','value1'], ])for.of循环for(let obj of h){ console.log(obj) }模块化export import// export 导出命令 calss Util{ sum=(a,b)=>a+b; } export default Util // import加载 import Util from './Util'原文链接:https://blog.csdn.net/qq_35349982/article/details/103581101
2019年12月19日
2,446 阅读
3 评论
1 点赞
2019-11-06
Spring Boot 自定义异步线程池的两种方式
SpringBoot 使用异步线程池方式如下第一种创建自定义线程池配置类,AsyncTaskExecutePool@EnableAsync @Configuration public class AsyncTaskExecutePool { //核心线程池大小 private final int corePoolSize = 10; //最大线程数 private final int maxPoolSize = 15; //队列容量 private final int queueCapacity = 50; //活跃时间/秒 private final int keepAliveSeconds = 60; @Bean public Executor myAsyncTaskPool() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心线程池大小 executor.setCorePoolSize(corePoolSize); //最大线程数 executor.setMaxPoolSize(maxPoolSize); //队列容量 executor.setQueueCapacity(queueCapacity); //活跃时间 executor.setKeepAliveSeconds(keepAliveSeconds); //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean executor.setWaitForTasksToCompleteOnShutdown(true); //线程名字前缀 executor.setThreadNamePrefix("my-async1--"); // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }创建任务处理类AsyncTask@Component @Slf4j public class AsyncTask { /** * myAsyncTaskPool 线程池的方法名,此处如果不写,会使用Spring默认的线程池 * @param i */ @Async("myAsyncTaskPool") public void run(int i){ log.info("我是:" + i); } }测试线程池AppTests@SpringBootTest class AppTests { @Autowired private AsyncTask asyncTask; @Test void test(){ for (int i = 0; i < 100; i++) { asyncTask.run(i); } } } 运行查看效果第二种第二种方式是重写 spring 默认线程池,使用这种方式的好处是可以直接使用 @Async 注解创建配置类AsyncTaskExecutePool1 并且实现AsyncConfigurer 类@Slf4j @EnableAsync @Configuration public class AsyncTaskExecutePool1 implements AsyncConfigurer { //核心线程池大小 private final int corePoolSize = 10; //最大线程数 private final int maxPoolSize = 15; //队列容量 private final int queueCapacity = 50; //活跃时间/秒 private final int keepAliveSeconds = 60; @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心线程池大小 executor.setCorePoolSize(corePoolSize); //最大线程数 executor.setMaxPoolSize(maxPoolSize); //队列容量 executor.setQueueCapacity(queueCapacity); //活跃时间 executor.setKeepAliveSeconds(keepAliveSeconds); //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean executor.setWaitForTasksToCompleteOnShutdown(true); //线程名字前缀 executor.setThreadNamePrefix("my-async-"); // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } /** * 异步任务异常处理 * @return */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (throwable, method, objects) -> { log.error("===="+throwable.getMessage()+"====", throwable); log.error("exception method:"+method.getName()); }; } }修改AsyncTask 类,在类中加入方法run1@Async public void run1(int i){ log.info("我是:" + i); }测试,在AppTests 中加入方法test1@Test void test1(){ for (int i = 0; i < 100; i++) { asyncTask.run1(i); } }运行查看效果注意同类中调用带有@Async 的方法是不生效的例子中的参数根据具体的需求修改源码本文源码:https://github.com/elunez/spring-boot-learn
2019年11月06日
3,712 阅读
0 评论
1 点赞
2019-10-17
Spring boot 整合 FreeMarker 实现代码生成功能
在我们开发一个新的功能的时候,会根据表创建Entity,Controller,Service,Repository等代码,其中很多步骤都是重复的,并且特别繁琐。这个时候就需要一个代码生成器帮助我们解决这个问题从而提高工作效率,让我们更致力于业务逻辑。设计原理在我们安装数据库后会有几个默认的数据库,其中information_schema这个数据库中保存了MySQL服务器所有数据库的信息,如:数据库名、数据库表、表的数据信息与访问权限等。information_schema的表tables记录了所有数据库的表的信息 information_schema的表columns记录了所有数据库的表字段详细的信息我们代码中可以可以通过Sql语句查询出当前数据库中所有表的信息,这里已 eladmin 为例。# 显示部分数据:表名称、数据库引擎、编码、表备注、创建时间 select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables where table_schema = (select database());知道表的数据后,可以查询出表字段的详细数据,这里用 job 表为例sql语句如下:# 显示部分数据:字段名称、字段类型、字段注释、字段键类型等 select column_name, is_nullable, data_type, column_comment, column_key, extra from information_schema.columns where table_schema = (select database()) and table_name = "job";有了表字段信息的数据后,通过程序将数据库表字段类型转换成Java语言的字段类型,再通过FreeMarker创建模板,将数据写入到模板,输出成文件即可实现代码生成功能。代码实现这里只贴出核心代码,源码可查询文末地址,首先创建一个新的spring boot 项目,选择如下依赖Maven完整依赖如下<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <!-- 配置管理工具 --> <dependency> <groupId>commons-configuration</groupId> <artifactId>commons-configuration</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>项目结构如下教程开始修改Spring boot 配置文件 application.yml,如下service: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/eladmin?serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver jpa: show-sql: true在 resources 目录下创建 Mysql 字段与 Java字段对应关系的配置文件 generator.properties,生成代码时字段转换时使用tinyint=Integer smallint=Integer mediumint=Integer int=Integer integer=Integer bigint=Long float=Float double=Double decimal=BigDecimal bit=Boolean char=String varchar=String tinytext=String text=String mediumtext=String longtext=String date=Timestamp datetime=Timestamp timestamp=Timestamp在 vo 包下创建临时 Vo 类 ColumnInfo,该类的功能用于接收Mysql字段详细信息import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class ColumnInfo { /** 数据库字段名称 **/ private Object columnName; /** 允许空值 **/ private Object isNullable; /** 数据库字段类型 **/ private Object columnType; /** 数据库字段注释 **/ private Object columnComment; /** 数据库字段键类型 **/ private Object columnKey; /** 额外的参数 **/ private Object extra; }在 util 包下创建字段工具类 ColumnUtil,该类的功能用于转换mysql类型为Java字段类型,同时添加驼峰转换方法,将表名转换成类名import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; /** * sql字段转java * * @author jie * @date 2019-01-03 */ public class ColumnUtil { private static final char SEPARATOR = '_'; /** * 获取配置信息 */ public static PropertiesConfiguration getConfig() { try { return new PropertiesConfiguration("generator.properties"); } catch (ConfigurationException e) { e.printStackTrace(); } return null; } /** * 转换mysql数据类型为java数据类型 * @param type * @return */ public static String cloToJava(String type){ Configuration config = getConfig(); return config.getString(type,null); } /** * 驼峰命名法工具 * * @return toCamelCase(" hello_world ") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toCamelCase(String s) { if (s == null) { return null; } s = s.toLowerCase(); StringBuilder sb = new StringBuilder(s.length()); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == SEPARATOR) { upperCase = true; } else if (upperCase) { sb.append(Character.toUpperCase(c)); upperCase = false; } else { sb.append(c); } } return sb.toString(); } /** * 驼峰命名法工具 * * @return toCamelCase(" hello_world ") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toCapitalizeCamelCase(String s) { if (s == null) { return null; } s = toCamelCase(s); return s.substring(0, 1).toUpperCase() + s.substring(1); } }在 util 包下创建代码生成工具类 GeneratorUtil,该类用于将获取到的Mysql字段信息转出Java字段类型,并且获取代码生成的路径,读取 Template,并且输出成文件,代码如下:import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import lombok.extern.slf4j.Slf4j; import org.springframework.util.ObjectUtils; import java.io.*; import java.time.LocalDate; import java.util.*; /** * 代码生成 * * @author jie * @date 2019-01-02 */ @Slf4j public class GeneratorUtil { private static final String TIMESTAMP = "Timestamp"; private static final String BIGDECIMAL = "BigDecimal"; private static final String PK = "PRI"; private static final String EXTRA = "auto_increment"; /** * 生成代码 * @param columnInfos * @param pack * @param author * @param tableName * @throws IOException */ public static void generatorCode(List<ColumnInfo> columnInfos, String pack, String author, String tableName) throws IOException { Map<String, Object> map = new HashMap<>(); map.put("package", pack); map.put("author", author); map.put("date", LocalDate.now().toString()); map.put("tableName", tableName); // 转换为小写开头的的类名, hello_world == helloWorld String className = ColumnUtil.toCapitalizeCamelCase(tableName); // 转换为大写开头的类名, hello_world == HelloWorld String changeClassName = ColumnUtil.toCamelCase(tableName); map.put("className", className); map.put("changeClassName", changeClassName); // 是否包含 Timestamp 类型 map.put("hasTimestamp", false); // 是否包含 BigDecimal 类型 map.put("hasBigDecimal", false); // 是否为自增主键 map.put("auto", false); List<Map<String, Object>> columns = new ArrayList<>(); for (ColumnInfo column : columnInfos) { Map<String, Object> listMap = new HashMap<>(); listMap.put("columnComment", column.getColumnComment()); listMap.put("columnKey", column.getColumnKey()); String colType = ColumnUtil.cloToJava(column.getColumnType().toString()); String changeColumnName = ColumnUtil.toCamelCase(column.getColumnName().toString()); if (PK.equals(column.getColumnKey())) { map.put("pkColumnType", colType); map.put("pkChangeColName", changeColumnName); } if (TIMESTAMP.equals(colType)) { map.put("hasTimestamp", true); } if (BIGDECIMAL.equals(colType)) { map.put("hasBigDecimal", true); } if (EXTRA.equals(column.getExtra())) { map.put("auto", true); } listMap.put("columnType", colType); listMap.put("columnName", column.getColumnName()); listMap.put("isNullable", column.getIsNullable()); listMap.put("changeColumnName", changeColumnName); columns.add(listMap); } map.put("columns", columns); Configuration configuration = new Configuration(Configuration.VERSION_2_3_23); configuration.setClassForTemplateLoading(GeneratorUtil.class, "/template"); Template template = configuration.getTemplate("Entity.ftl"); // 获取文件路径 String filePath = getAdminFilePath(pack, className); File file = new File(filePath); // 生成代码 genFile(file, template, map); } /** * 定义文件路径以及名称 */ private static String getAdminFilePath(String pack, String className) { String ProjectPath = System.getProperty("user.dir") + File.separator; String packagePath = ProjectPath + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator; if (!ObjectUtils.isEmpty(pack)) { packagePath += pack.replace(".", File.separator) + File.separator; } return packagePath + "entity" + File.separator + className + ".java"; } private static void genFile(File file, Template template, Map<String, Object> params) throws IOException { File parentFile = file.getParentFile(); // 创建目录 if (null != parentFile && !parentFile.exists()) { parentFile.mkdirs(); } //创建输出流 Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); //输出模板和数据模型都对应的文件 try { template.process(params, writer); } catch (TemplateException e) { e.printStackTrace(); } } }在 resources 的 template 目录下创建 framework 模板 Entity.ftl,代码如下:package ${package}.entity; import lombok.Data; import javax.persistence.*; <#if hasTimestamp> import java.sql.Timestamp; </#if> <#if hasBigDecimal> import java.math.BigDecimal; </#if> import java.io.Serializable; /** * @author ${author} * @date ${date} */ @Entity @Data @Table(name="${tableName}") public class ${className} implements Serializable { <#if columns??> <#list columns as column> <#if column.columnComment != ''> // ${column.columnComment} </#if> <#if column.columnKey = 'PRI'> @Id <#if auto> @GeneratedValue(strategy = GenerationType.IDENTITY) </#if> </#if> @Column(name = "${column.columnName}"<#if column.columnKey = 'UNI'>,unique = true</#if><#if column.isNullable = 'NO' && column.columnKey != 'PRI'>,nullable = false</#if>) private ${column.columnType} ${column.changeColumnName}; </#list> </#if> }创建服务类 GeneratorService,该类用于获取数据库表的源数据import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * 代码生成服务 */ @Service public class GeneratorService { @PersistenceContext private EntityManager em; public List<ColumnInfo> getColumns(String tableName) { StringBuilder sql = new StringBuilder("select column_name, is_nullable, data_type, column_comment, column_key, extra from information_schema.columns where "); if(!ObjectUtils.isEmpty(tableName)){ sql.append("table_name = '").append(tableName).append("' "); } sql.append("and table_schema = (select database()) order by ordinal_position"); Query query = em.createNativeQuery(sql.toString()); List result = query.getResultList(); List<ColumnInfo> columnInfos = new ArrayList<>(); for (Object o : result) { Object[] obj = (Object[])o; columnInfos.add(new ColumnInfo(obj[0],obj[1],obj[2],obj[3],obj[4],obj[5])); } return columnInfos; } }由于没有前端页面,所以只能在测试类中演示代码生成功能,GeneratorDomeApplicationTests 修改如下import com.ydyno.util.GeneratorUtil; import com.ydyno.vo.ColumnInfo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; import java.util.List; @SpringBootTest class GeneratorDomeApplicationTests { @Autowired private GeneratorService generatorService; @Test void genTest() throws IOException { String tableName = "job"; String pack = "com.ydyno"; String author = "Zheng Jie"; List<ColumnInfo> columnInfos = generatorService.getColumns(tableName); GeneratorUtil.generatorCode(columnInfos,pack,author,tableName); } }执行后,查看创建好的Entity
2019年10月17日
7,288 阅读
1 评论
1 点赞
2019-07-09
持续集成工具 Jenkins 介绍与安装
我们在项目开发过程中,需要将已开发完的功能提交到 Git 上,然后构建与发布。如果更新很频繁,这将变得非常繁琐,并且会浪费大量时间。使用Jenkins就可以解决这个问题,当代码提交时就可以通过Jenkins自动构建与发布项目。什么是持续集成持续集成就是每完成一部分功能就向下个环节交付,通过快速的版本迭代,尽早的发现存在的问题以便开发人员修复。一个完整的持续集成系统应包含如下内容:1、一个自动构建过程(自动编译、分发、部署和测试等)2、一个代码存储库(版本控制与维护)3、一个持续集成服务器(Jenkins)什么是JenkinsJenkins是一个开源的持续集成(CI)工具,主要用于持续、自动的构建/测试软件项目。Jenkins用Java语言编写,使用时必须配置JDk环境。Jenkins 通常与版本管理工具(Git、Svn)和构建工具(Maven、Gradle)结合使用。Jenkins拥有丰富的插件库,使用Jenkins可以帮助我们自动构建各类项目Jenkins 安装安装JDK环境# 检索1.8的列表 yum list java-1.8* # 安装JDK yum install java-1.8.0-openjdk* -y # 测试 java -version安装Jenkins# 新建文件夹并且定位到改目录 mkdir /usr/local/jenkins && cd /usr/local/jenkins # 下载安装包 wget http://mirrors.jenkins-ci.org/war/latest/jenkins.war # 安装Screen,以便后台运行 yum install screen # 启动应用 nohup java -jar /usr/local/jenkins/jenkins.war --httpPort=8000 &进入系统启动应用后,在浏览器输入:ip:端口Jenkins 第一次启动时会在控制台打印出密码或者使用提示中的路径获取密码cat /root/.jenkins/secrets/initialAdminPassword进入系统后,设置用户名与密码即可
2019年07月09日
1,192 阅读
0 评论
1 点赞
1
2
3