懒人方案–半天搞定一个SpringBoot单体项目
文章目录
前言
好久木有冒个泡了,来活跃一下,顺便再水一篇博文~。那么最近也是在构建咱们这个whiteHole的分布式版本的时候呢,发现一个问题那就是通过充分考量业务的分析之后,鄙人一共创建了90多张表,6个数据库,还有两个没有创建(附加功能)保守估计加上一套完整的分级管理系统也就是120/30多张表嘛。
那么问题来了,有没有一张方案能够给我偷个懒呢,把这种简单的controller service dao 最好再来点前端页面给我写好呢?
答案是有的,如果熟练掌握了这个工具的使用,那么你像咱们C站或者某音那种博主一样,一个礼拜好几个xx管理项目拿过来圈粉是完全没问题的。只是文档稍微麻烦一点,当然也可以自动生成嘛。总之本文的目的就是教你如何合理的偷懒,一个礼拜N个项目还能赚赚外快是吧。
当然这也仅限于这种xx后台管理系统这也玩意,或者是不上线的玩意,因为这个还是一个毛坯房,有些东西还是要自己改一改的,不够你要是是毛坯房也够用的话,那也可以,毕竟像xx后台管理,或者xx大作业基本上不用考虑别的事情,不用那么麻烦。
工具下载
ok,废话不多说,我们开始,首先我们需要去获取我们的一个生成器,那么这个玩意的话,也是很早以前就有了的,再次突出:都2202年!当然偷懒的前提是已近掌握了。
我们先进入项目地址:https://github.com/renrenio/
这个项目里面的话是有好几个项目的,这里简单介绍一下。
renren-fast-vue
这个玩意是一套后端的管理系统,很多东西也是构建好了的,拿来用,改一下配就好了。那么这个是前后端分离的一个前端项目,是基于vue+elementui 做的。
renren-fast
这个是和咱们fast-vue配套的后端
其他的官网都有介绍。我这里就挑几个来look,look。
那么咱们这里还有使用到的呢就是 renren-generator 也就是咱们的代码生成器。
数据库创建
由于这个代码生成器主要是通过数据库,自动生成咱们的controller service dao 层,当然用mybatisplus其实也可以自动生成dao层,然后是基本的service,但是这里还有controller层,还有一些前端的代码生成(这个代码生的是vue+elementui,可以直接copy到你的前端工程)
这里的话,我们就拿WhiteHoleCloud的项目来做演示了。首先来看到咱们的这个项目吧
这里是集成了它的后台和生成器,这个东西看你自己放在哪,我这边就先这样了。
我们用来演示的是user服务。那么对应的表是这张表:
环境准备
现在我们已经有了数据库,表啥的都建好了。
那么我们下载好源码
这个咋下载我就不说了,之后的话放在一共合适的地方在你的idea里面打开。我这里就放在了WhiteHoleCloud的项目下。
之后展开 :
这里注意下 tablePrefix表的前缀,我这个是user服务,所以前缀都是user_
然后我们运行它的Application
我这里启动9000端口(原来的8000被用了)
然后选择一下你的表,之后生成就好了,然后你会得到一个压缩包。
这里面有一些前端的代码,就在views下面,是vue+element写的
然后这里面还有提供了mapper,当然实际上生成的代码其实是mybatisplus的是注解式的。如果你有需要就导入也可以。
比如我这样就是这样的:
这里注意一点是我用idea把user这个包改了个名字,前面配置的时候写错了。
依赖导入
Maven依赖导入
现在的话我们是成功把代码迁移过来了,但是里面还有很多东西没有,最基本的就是依赖没有。
这里的话由于我是一个分布式的项目,所以的话,我这边有一个组件包 。然后我把依赖都放在这里面了,当然也可以放在root的pom文件下,但是还有一些包没有所以我直接创建组件来用。那么如果你是单体项目的话,那么你直接放在你那个项目的pom文件下,例如:
但是咱们这里不是这样的,不过都是一样的。
基本依赖如下:
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.15</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.60</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.13</version>
</dependency>
</dependencies>
那么这个依赖我要说一下的就是,我这里还少了这个shiro的依赖,因为我要用的是SpringSecurity。
如果你要用Shiro的话你自己再导入进去就好了,我这里的话就不导入了,而且我还把Shiro相关的代码注释了。
那么如果你们自己的话,那就看情况了。
代码依赖
这个玩意毕竟是代码生成的嘛,还有一些它自己的代码依赖是需要导入的,这个可以去copy一下,你自己也可以去copy一下,但是注意的是要去renren-fast这个项目里面的代码去copy。
那么我这里的话就直接贴出来,你先把Maven依赖导入,然后创建对应的包,把这个代码拷贝进去,那个Maven依赖里面有些就是为这个代码依赖服务的。所以直接copy这里是不错的选择。
我把这些代码都放在了那个公共组件里面,那么如果你是单体的项目,那么你把common这个包创建在你的项目目录下就好了。
那么现在我就依次把对应的代码给出了,自己创建好后,复制就好了。
exception
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.exception;
/**
* 自定义异常
*
* @author Mark [email protected]
*/
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg) {
super(msg);
this.msg = msg;
}
public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
utils
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
* <p>
* https://www.renren.io
* <p>
* 版权所有,侵权必究!
*/
package com.huterox.common.utils;
import com.huterox.common.validator.group.AliyunGroup;
import com.huterox.common.validator.group.QcloudGroup;
import com.huterox.common.validator.group.QiniuGroup;
import java.util.Optional;
import java.util.stream.Stream;
/**
* 常量
*
* @author Mark [email protected]
*/
public class Constant {
/**
* 超级管理员ID
*/
public static final int SUPER_ADMIN = 1;
/**
* 当前页码
*/
public static final String PAGE = "page";
/**
* 每页显示记录数
*/
public static final String LIMIT = "limit";
/**
* 排序字段
*/
public static final String ORDER_FIELD = "sidx";
/**
* 排序方式
*/
public static final String ORDER = "order";
/**
* 升序
*/
public static final String ASC = "asc";
/**
* 菜单类型
*
* @author chenshun
* @email [email protected]
* @date 2016年11月15日 下午1:24:29
*/
public enum MenuType {
/**
* 目录
*/
CATALOG(0),
/**
* 菜单
*/
MENU(1),
/**
* 按钮
*/
BUTTON(2);
private int value;
MenuType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
/**
* 定时任务状态
*
* @author chenshun
* @email [email protected]
* @date 2016年12月3日 上午12:07:22
*/
public enum ScheduleStatus {
/**
* 正常
*/
NORMAL(0),
/**
* 暂停
*/
PAUSE(1);
private int value;
ScheduleStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
/**
* 云服务商
*/
public enum CloudService {
/**
* 七牛云
*/
QINIU(1, QiniuGroup.class),
/**
* 阿里云
*/
ALIYUN(2, AliyunGroup.class),
/**
* 腾讯云
*/
QCLOUD(3, QcloudGroup.class);
private int value;
private Class<?> validatorGroupClass;
CloudService(int value, Class<?> validatorGroupClass) {
this.value = value;
this.validatorGroupClass = validatorGroupClass;
}
public int getValue() {
return value;
}
public Class<?> getValidatorGroupClass() {
return this.validatorGroupClass;
}
public static CloudService getByValue(Integer value) {
Optional<CloudService> first = Stream.of(CloudService.values()).filter(cs -> value.equals(cs.value)).findFirst();
if (!first.isPresent()) {
throw new IllegalArgumentException("非法的枚举值:" + value);
}
return first.get();
}
}
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.utils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.List;
/**
* 分页工具类
*
* @author Mark [email protected]
*/
public class PageUtils implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总记录数
*/
private int totalCount;
/**
* 每页记录数
*/
private int pageSize;
/**
* 总页数
*/
private int totalPage;
/**
* 当前页数
*/
private int currPage;
/**
* 列表数据
*/
private List<?> list;
/**
* 分页
* @param list 列表数据
* @param totalCount 总记录数
* @param pageSize 每页记录数
* @param currPage 当前页数
*/
public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
this.list = list;
this.totalCount = totalCount;
this.pageSize = pageSize;
this.currPage = currPage;
this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
}
/**
* 分页
*/
public PageUtils(IPage<?> page) {
this.list = page.getRecords();
this.totalCount = (int)page.getTotal();
this.pageSize = (int)page.getSize();
this.currPage = (int)page.getCurrent();
this.totalPage = (int)page.getPages();
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getCurrPage() {
return currPage;
}
public void setCurrPage(int currPage) {
this.currPage = currPage;
}
public List<?> getList() {
return list;
}
public void setList(List<?> list) {
this.list = list;
}
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.utils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huterox.common.xss.SQLFilter;
import org.apache.commons.lang.StringUtils;
import java.util.Map;
/**
* 查询参数
*
* @author Mark [email protected]
*/
public class Query<T> {
public IPage<T> getPage(Map<String, Object> params) {
return this.getPage(params, null, false);
}
public IPage<T> getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
//分页参数
long curPage = 1;
long limit = 10;
if(params.get(Constant.PAGE) != null){
curPage = Long.parseLong((String)params.get(Constant.PAGE));
}
if(params.get(Constant.LIMIT) != null){
limit = Long.parseLong((String)params.get(Constant.LIMIT));
}
//分页对象
Page<T> page = new Page<T>(curPage, limit);
//分页参数
params.put(Constant.PAGE, page);
//排序字段
//防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER_FIELD));
String order = (String)params.get(Constant.ORDER);
//前端字段排序
if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){
if(Constant.ASC.equalsIgnoreCase(order)) {
return page.addOrder(OrderItem.asc(orderField));
}else {
return page.addOrder(OrderItem.desc(orderField));
}
}
//没有排序字段,则不排序
if(StringUtils.isBlank(defaultOrderField)){
return page;
}
//默认排序
if(isAsc) {
page.addOrder(OrderItem.asc(defaultOrderField));
}else {
page.addOrder(OrderItem.desc(defaultOrderField));
}
return page;
}
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.utils;
import org.apache.http.HttpStatus;
import java.util.HashMap;
import java.util.Map;
/**
* 返回数据
*
* @author Mark [email protected]
*/
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 0);
put("msg", "success");
}
public static R error() {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}
validator
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 新增数据 Group
*
* @author Mark [email protected]
*/
public interface AddGroup {
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 阿里云
*
* @author Mark [email protected]
*/
public interface AliyunGroup {
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
import javax.validation.GroupSequence;
/**
* 定义校验顺序,如果AddGroup组失败,则UpdateGroup组不会再校验
*
* @author Mark [email protected]
*/
@GroupSequence({AddGroup.class, UpdateGroup.class})
public interface Group {
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 腾讯云
*
* @author Mark [email protected]
*/
public interface QcloudGroup {
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 七牛
*
* @author Mark [email protected]
*/
public interface QiniuGroup {
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 更新数据 Group
*
* @author Mark [email protected]
*/
public interface UpdateGroup {
}
xxs
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.xss;
import com.huterox.common.exception.RRException;
import org.apache.commons.lang.StringUtils;
/**
* SQL过滤
*
* @author Mark [email protected]
*/
public class SQLFilter {
/**
* SQL注入过滤
* @param str 待验证的字符串
*/
public static String sqlInject(String str){
if(StringUtils.isBlank(str)){
return null;
}
//去掉'|"|;|字符
str = StringUtils.replace(str, "'", "");
str = StringUtils.replace(str, """, "");
str = StringUtils.replace(str, ";", "");
str = StringUtils.replace(str, "\", "");
//转换成小写
str = str.toLowerCase();
//非法字符
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
//判断是否包含非法字符
for(String keyword : keywords){
if(str.indexOf(keyword) != -1){
throw new RRException("包含非法字符");
}
}
return str;
}
}
测试
ok,那么基本上就好了,我们测试一波。
我们先配置一下
如果是你自己的单体项目也一样。
然后我在controller里面访问一个接口看看。
ok,正常