项目介绍
微信商城+微信公众号开发,该项目根据上海某大型知名电商企业互联网互联网项目,改版而来,使用最新微服务技术,页面使用高仿小米界面。功能包含电商模块,会员、SSO、订单、商品、支付、消息、微信、H5和PC、移动端、优惠券、后台系统、任务调度等模块。
电商系统特点
1.技术新
2.技术范围广
3.分布式
4.高并发、集群、负载均衡、高并发
5.海量数据
6.业务复杂
7.系统安全
电商系统架构
项目演变过程
传统架构
分布式架构
什么是分布式?
根据业务需求进行拆分成N个子系统,多个子系统相互协作才能完成业务流程子系统之间通讯使用RPC远程通讯技术。
什么是集群
同一个工程部署在多个不同的服务器上。
分布式架构优点
1.把模块拆分,使用接口通信,降低模块之间的耦合度。
2.把项目拆分成若干个子项目,不同的团队负责不同的子项目。
3.增加功能时只需要再增加一个子项目,调用其它系统的接口就可以。
4.可以灵活的进行分布式部署。
有优点就有缺点,缺点如下:
1.系统之间交互需要使用远程通信,接口开发增加工作量。
2.各个模块有一些通用的业务逻辑无法共用。
为了解决上面分布式架构的缺点,我们引入了soa架构,SOA:Service Oriented Architecture面向服务的架构。也就是把工程拆分成服务层、表现层两个工程。服务层中包含业务逻辑,只需要对外提供服务即可。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。
项目拆分
在大型电商项目中,会将一个大的项目,拆分成N多个子模块,分配给不同的团队开发。
团队之间通讯采用RPC远程调用技术、使用Http+Restful+Json传输。
接口服务
会员服务、订单服务、商品服务、支付服务、消息服务、秒杀服务、优惠券服务等。
项目工程
H5项目、微信项目、后台管理等。
使用技术
电商项目
SpringBoot+SpringCloud +Maven+Redis+ActiveMQ+XXLJOB(分布式任务调度)+ Freemarker等。
使用 SpringCloud Eureka作为注册中心、Feign客户端调用工具、断路器Hystrix
视图展示使用Freemarker、数据库层使用Mybatis框架、缓存使用Redis、数据库使用MySQL
项目管理工具使用Maven、版本控制工具使用SVN、项目自动部署工具使用Jenkins
消息中间件使用ActiveMQ、分布式任务调度系统使用XXLJOB、反向代理工具使用Nginx
日志管理插件工具使用lombok、分布式日志收集使用Logstash、解析JSON框架使用FastJson
数据安全加密使用MD5加盐和Base64、RSA、分布式文件存储系统FastDFS等。
支付网关接口使用支付宝、第三方登录使用QQ授权等。
项目构建
newbies-shopp-parent
├─newbies-shopp-common // 抽取的公共模块
├─newbies-shopp-eurekaserver // eureka注册中心
├─newbies-shopp-api // api服务
├─newbies-shopp-member-api // 会员服务
├─newbies-shopp-order-api // 订单服务
├─newbies-shopp-goods-api // 商品服务
├─newbies-shopp-pay-api // 支付服务
├─newbies-shopp-member // 会员系统
├─newbies-shopp-nessage // 消息系统
├─newbies-shopp-mobile-web // h5端工程
创建Modules
环境搭建
环境搭建步骤
创建项目
引入依赖
搭建eureka注册中心
封装控制层、日志、常量、常用工具、Basedao
newbies-shopp-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 集成commons工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<!-- 集成lombok 框架 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 集成redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 集成aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 集成web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot整合activemq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!-- 集成发送邮件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 集成mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.3.7</version>
</dependency>
<!-- 阿里巴巴数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.30</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
newbies-shopp-common
Maven依赖
<parent>
<groupId>com.newbies</groupId>
<artifactId>newbies-shopp-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>newbies-shopp-common</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
newbies-shopp-eurekaserver
Maven依赖
<parent>
<groupId>com.newbies</groupId>
<artifactId>newbies-shopp-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.newbies</groupId>
<artifactId>newbies-shopp-eurekaservers</artifactId>
<version>0.0.1-SNAPSHOT</version>
启动EureKaServer
创建eureka作为服务注册中心
@SpringBootApplication
@EnableEurekaServer
public class EureKaServer {
public static void main(String[] args) {
SpringApplication.run(EureKaServer.class, args);
}
}
application.yml
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
newbies-shopp-api
创建newbies-shopp-api工程,存放所有的需要提供给外部接口项目
newbies-shopp-member-api
创建MemberService测试接口
@RequestMapping("/member")
public interface MemberService {
@RequestMapping("/testRest")
public Map<String, Object> testRest();
}
newbies-shopp-member
Maven依赖
<dependencies>
<dependency>
<groupId>com.newbies</groupId>
<artifactId>newbies-shopp-member-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.newbies</groupId>
<artifactId>newbies-shopp-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- springboot整合mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
配置文件
server:
port: 8762
# context-path: /member
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: member
实现接口MemberServiceImpl
@RestController
public class MemberServiceImpl implements MemberService {
@Override
public Map<String, Object> testRest() {
Map<String, Object> result = new HashMap<>();
result.put("errorCode", "200");
result.put("errorMsg", "success");
return result;
}
}
工具类封装
创建ResponseBase
public class ResponseBase {
// 响应code
private Integer code;
// 消息内容
private String msg;
// 返回data
private Object data;
public ResponseBase() {
}
public ResponseBase(Integer code, String msg, Object data) {
super();
this.code = code;
this.msg = msg;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
BaseController
public class BaseController {
// 返回成功 ,data值为null
public ResponseBase setResultSuccess() {
return setResult(Constants.HTTP_RES_CODE_200, Constants.HTTP_RES_CODE_200_VALUE, null);
}
// 返回成功 ,data可传
public ResponseBase setResultSuccess(Object data) {
return setResult(Constants.HTTP_RES_CODE_200, Constants.HTTP_RES_CODE_200_VALUE, data);
}
// 返回失败
public ResponseBase setResultError(String msg){
return setResult(Constants.HTTP_RES_CODE_500,msg, null);
}
// 自定义返回结果
public ResponseBase setResult(Integer code, String msg, Object data) {
ResponseBase responseBase = new ResponseBase();
responseBase.setCode(code);
responseBase.setMsg(msg);
if (data != null)
responseBase.setData(data);
return responseBase;
}
}
ListUtils封装
public class ListUtils {
//判断list集合是否为空
public List<?> emptyList(List<?> list) {
if (list == null || list.size() <= 0) {
return null;
}
return list;
}
//判断map集合是否为空
public Map<?,?> emptyMap(Map<?,?> map) {
if (map == null || map.size() <= 0) {
return null;
}
return map;
}
}
Constants
public interface Constants {
// 响应code
String HTTP_RES_CODE_NAME = "code";
// 响应msg
String HTTP_RES_CODE_MSG = "msg";
// 响应data
String HTTP_RES_CODE_DATA = "data";
// 响应请求成功
String HTTP_RES_CODE_200_VALUE = "success";
// 系统错误
String HTTP_RES_CODE_500_VALUE = "fial";
// 响应请求成功code
Integer HTTP_RES_CODE_200 = 200;
// 系统错误
Integer HTTP_RES_CODE_500 = 500;
}
BaseRedis
@SuppressWarnings({ "rawtypes", "unchecked" })
@Component
public class BaseRedisService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public void setString(String key, Object data, Long timeout) {
if (data instanceof String) {
String value = (String) data;
stringRedisTemplate.opsForValue().set(key, value);
}
if (timeout != null) {
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
}
public Object getString(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
public void delKey(String key) {
stringRedisTemplate.delete(key);
}
}
Linux环境下安装redis
linux 安装redis
Redis的官方下载网址是:Redis (这里下载的是Linux版的Redis源码包)
Redis服务器端的默认端口是6379。
这里以虚拟机中的Linux系统如何安装Redis进行讲解。
在windows系统中下载好Redis的源码包。
1. 通过WinSCP工具,将Redis的源码包由windows上传到Linux系统的这个目录/opt/redis (即根目录下的lamp文件夹)。
2. 解压缩。
tar -zxf redis-2.6.17.tar.gz
3. 切换到解压后的目录。
cd redis-2.6.17 ( 一般来说,解压目录里的INSTALL文件或README文件里写有安装说明,可参考之)
4. 编译。
make
(注意,编译需要C语言编译器gcc的支持,如果没有,需要先安装gcc。可以使用rpm -q gcc查看gcc是否安装)
(利用yum在线安装gcc的命令 yum -y install gcc )
(如果编译出错,请使用make clean清除临时文件。之后,找到出错的原因,解决问题后再来重新安装。 )
5. 进入到src目录。
cd src
6. 执行安装。
make install
到此就安装完成。但是,由于安装redis的时候,我们没有选择安装路径,故是默认位置安装。在此,我们可以将可执行文件和配置文件移动到习惯的目录。
cd /usr/local
mkdir -p /usr/local/redis/bin
mkdir -p /usr/local/redis/etc
cd /lamp/redis-2.6.17
mv ./redis.conf /usr/local/redis/etc
cd src
mv mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-dump redis-cli redis-server redis-sentinel /usr/local/redis/bin
7.开放linux 6379 端口
1.编辑 /etc/sysconfig/iptables 文件:vi /etc/sysconfig/iptables
加入内容并保存:-A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp –dport 6379 -j ACCEPT
2.重启服务:/etc/init.d/iptables restart
3.查看端口是否开放:/sbin/iptables -L -n
比较重要的3个可执行文件:
redis-server:Redis服务器程序
redis-cli:Redis客户端程序,它是一个命令行操作工具。也可以使用telnet根据其纯文本协议操作。
redis-benchmark:Redis性能测试工具,测试Redis在你的系统及配置下的读写性能。
Redis的启动命令:
/usr/local/redis/bin/redis-server
或
cd /usr/local/redis/bin
./redis-server /usr/local/redis/etc/redis.conf 为redis-server指定配置文
修改 redis.conf文件
daemonize yes --- 修改为yes 后台启动
requirepass 123456 ----注释取消掉设置账号密码
ps aux | grep '6379' --- 查询端口
kill -15 9886 --- 杀死重置
kill -9 9886 --- 强制杀死
service iptables stop 停止防火强
redis命令连接方式
./redis-cli -h 127.0.0.1 -p 6379 -a "123456" --- redis 使用账号密码连接
PING 结果表示成功
SpringBoot整合Redis
步骤引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Redis封装Java
在newbies-shopp-common项目下创建一个BaseRedisService
@Component
public class BaseRedisService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public void setString(String key, Object data) {
setString(key, data, null);
}
public void setString(String key, Object data, Long timeout) {
if (data instanceof String) {
String value = (String) data;
stringRedisTemplate.opsForValue().set(key, value);
}
if (timeout != null) {
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
}
public String getString(String key) {
return (String) stringRedisTemplate.opsForValue().get(key);
}
public void delKey(String key) {
stringRedisTemplate.delete(key);
}
}
配置文件新增redis连接
spring:
redis:
host: 127.0.0.1
password: 123456
port: 6379
pool:
max-idle: 100
min-idle: 1
max-active: 1000
max-wait: -1
测试结果
MemberService
@RequestMapping("/setRedisTest")
public ResponseBase setRedisTest(String key, String value);
@RequestMapping("/getRedis")
public ResponseBase getRedis(String key);
MemberServiceImpl
@Override
public ResponseBase setRedisTest(String key, String value) {
baseRedisService.setString(key, value);
return setResultSuccess();
}
@Override
public ResponseBase getRedis(String key) {
String value = baseRedisService.getString(key);
return setResultSuccess(value);
}
日志
安装lomBok插件
1.下载lombok.jar包https://projectlombok.org/download.html
2.运行Lombok.jar: Java -jar D:\software\lombok.jar D:\software\lombok.jar这是windows下lombok.jar所在的位置
数秒后将弹出一框,以确认eclipse的安装路径</code>
3.确认完eclipse的安装路径后,点击install/update按钮,即可安装完成
4.安装完成之后,请确认eclipse安装路径下是否多了一个lombok.jar包,并且其
配置文件eclipse.ini中是否 添加了如下内容: </code>
-javaagent:lombok.jar
-Xbootclasspath/a:lombok.jar
那么恭喜你已经安装成功,否则将缺少的部分添加到相应的位置即可 </code>
重启eclipse或myeclipse
Lombok作用
使用注解版本,生成get和set方法、简化重复代码
Maven坐标
<!-- 集成lombok 框架 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
生成get或set方法
@Getter
public class TestEntity {
private String userId;
private String userName;
// public String getUserId() {
//
// return userId;
// }
// public void setUserId(String userId) {
//
// this.userId = userId;
// }
// public String getUserName() {
//
// return userName;
// }
// public void setUserName(String userName) {
//
// this.userName = userName;
// }
public static void main(String[] args) {
//使用
new TestEntity().getUserId();
}
}
打印日志
@Slf4j
@RestController
public class MemberServiceImpl extends BaseApiRedisService implements MemberService {
@Autowired
private BaseRedisService baseRedisService;
@Override
public Map<String, Object> index() {
String result = "644064";
log.info("request .... index result:{}",result);
return setResultData(result);
}
}
使用aop打印请求参数
@Aspect
// 申明是个spring管理的bean
@Component
@Slf4j
public class LogAspectServiceApi {
private JSONObject jsonObject = new JSONObject();
// 申明一个切点 里面是 execution表达式
@Pointcut("execution(public * com.newbies.service.*.*(..))")
private void controllerAspect() {
}
// 请求method前打印内容
@Before(value = "controllerAspect()")
public void methodBefore(JoinPoint joinPoint) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
log.info("===============请求内容===============");
try {
// 打印请求内容
log.info("请求地址:" + request.getRequestURL().toString());
log.info("请求方式:" + request.getMethod());
log.info("请求类方法:" + joinPoint.getSignature());
log.info("请求类方法参数:" + Arrays.toString(joinPoint.getArgs()));
} catch (Exception e) {
log.error("###LogAspectServiceApi.class methodBefore() ### ERROR:", e);
}
log.info("===============请求内容===============");
}
// 在方法执行完结后打印返回内容
@AfterReturning(returning = "o", pointcut = "controllerAspect()")
public void methodAfterReturing(Object o) {
log.info("--------------返回内容----------------");
try {
log.info("Response内容:" + jsonObject.toJSONString(o));
} catch (Exception e) {
log.error("###LogAspectServiceApi.class methodAfterReturing() ### ERROR:", e);
}
log.info("--------------返回内容----------------");
}
}
日志收集
logback.xm
DateUtils
@Slf4j
public class DateUtils {
/** 年-月-日 时:分:秒 显示格式 */
// 备注:如果使用大写HH标识使用24小时显示格式,如果使用小写hh就表示使用12小时制格式。
public static String DATE_TO_STRING_DETAIAL_PATTERN = "yyyy-MM-dd HH:mm:ss";
/** 年-月-日 显示格式 */
public static String DATE_TO_STRING_SHORT_PATTERN = "yyyy-MM-dd";
private static SimpleDateFormat simpleDateFormat;
/**
* Date类型转为指定格式的String类型
*
* @param source
* @param pattern
* @return
*/
public static String DateToString(Date source, String pattern) {
simpleDateFormat = new SimpleDateFormat(pattern);
return simpleDateFormat.format(source);
}
/**
*
* unix时间戳转为指定格式的String类型
*
*
* System.currentTimeMillis()获得的是是从1970年1月1日开始所经过的毫秒数
* unix时间戳:是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒
*
* @param source
* @param pattern
* @return
*/
public static String timeStampToString(long source, String pattern) {
simpleDateFormat = new SimpleDateFormat(pattern);
Date date = new Date(source * 1000);
return simpleDateFormat.format(date);
}
/**
* 将日期转换为时间戳(unix时间戳,单位秒)
*
* @param date
* @return
*/
public static long dateToTimeStamp(Date date) {
Timestamp timestamp = new Timestamp(date.getTime());
return timestamp.getTime() / 1000;
}
/**
*
* 字符串转换为对应日期(可能会报错异常)
*
* @param source
* @param pattern
* @return
*/
public static Date stringToDate(String source, String pattern) {
simpleDateFormat = new SimpleDateFormat(pattern);
Date date = null;
try {
date = simpleDateFormat.parse(source);
} catch (ParseException e) {
log.error("字符串转换日期异常", e);
}
return date;
}
/**
* 获得当前时间对应的指定格式
*
* @param pattern
* @return
*/
public static String currentFormatDate(String pattern) {
simpleDateFormat = new SimpleDateFormat(pattern);
return simpleDateFormat.format(new Date());
}
/**
* 获得当前unix时间戳(单位秒)
*
* @return 当前unix时间戳
*/
public static long currentTimeStamp() {
return System.currentTimeMillis() / 1000;
}
/**
*
* @methodDesc: 功能描述:(获取当前系统时间戳)
* @param: @return
*/
public static Timestamp getTimestamp() {
return new Timestamp(new Date().getTime());
}
// 待补充
MD5Util
public class MD5Util {
public final static String MD5(String s) {
char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
try {
byte[] btInput = s.getBytes();
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
System.out.println(MD5Util.MD5("20121221"));
System.out.println(MD5Util.MD5("加密"));
}
}
BaseDao
maven依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.3.7</version>
</dependency>
<!-- springboot整合mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
数据源连接
spring:
application:
name: member
#redis连接信息
redis:
host: 192.168.110.163
password: 123456
port: 6379
pool:
max-idle: 100
min-idle: 1
max-active: 1000
max-wait: -1
#数据库连接信息
datasource:
name: test
url: jdbc:mysql://127.0.0.1:3306/newbies-member
username: root
password: root
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
创建Baseentity
@Getter
@Setter
public class BaseEntity {
/**
* 主键ID
*/
private Long id;
/**
* 创建时间
*/
private Timestamp created;
/**
* 修改时间
*/
private Timestamp updated;
}
创建Basedao
/**
*
* @classDesc: 功能描述:(BaseDao)
* @author: 杨改革
* @QQ: 1320425613
* @微信:Yang_Gaige
* @createTime: 2021年10月24日 下午9:10:25
* @version: v1.0
* @copyright:每特学院(蚂蚁课堂)上海每特教育科技有限公司
*/
public interface BaseDao {
/**
*
*
* @methodDesc: 功能描述:(增加持久化对象)
* @param: @param
* t
*/
@InsertProvider(type = BaseProvider.class, method = "save")
public void save(@Param("oj") Object oj, @Param("table") String table);
/**
*
*
* @methodDesc: 功能描述:(修改持久化对象)
* @param: @param
* t
* @return
*/
@InsertProvider(type = BaseProvider.class, method = "update")
public void update(@Param("oj") Object oj, @Param("table") String table, @Param("idKey") Long idKey);
}
创建BaseProvider
public class BaseProvider {
public String save(Map<String, Object> para) {
final Object oj = para.get("oj");
final String table = (String) para.get("table");
String sql = new SQL() {
{
INSERT_INTO(table);
String columns = ReflectionUtils.getInsertFields(oj);
String values = ReflectionUtils.getInsertDeclaredFieldsValue(oj);
VALUES(columns, values);
}
}.toString();
return sql;
}
public String update(Map<String, Object> para) {
final Object oj = para.get("oj");
final String table = (String) para.get("table");
final Long idKey = (Long) para.get("idKey");
String sql = new SQL() {
{
UPDATE(table);
SET(ReflectionUtils.updateAllSerField(oj));
WHERE("id="+idKey + "");
}
}.toString();
return sql;
}
}
创建ReflectionUtils工具类
/**
*
* @classDesc: 功能描述:(Java反射工具类)
* @author: 杨改革
* @QQ: 1320425613
* @微信:Yang_Gaige
* @createTime: 2021年10月24日 下午9:51:54
* @version: v1.0
* @copyright:每特学院(蚂蚁课堂)上海每特教育科技有限公司
*/
@Slf4j
public class ReflectionUtils {
/**
*
* @methodDesc: 功能描述:(获取类的属性,拼接成字符串)
* @param: @return
*/
public static String getInsertFields(Object oj) {
if (oj == null) {
return null;
}
Class cl = oj.getClass();
// 获取所有的属性
Field[] declaredFields = cl.getDeclaredFields();
String sb1 = appendFields(declaredFields);
Class superclass = cl.getSuperclass();
Field[] superField = superclass.getDeclaredFields();
String sb2 = appendFields(superField);
return sb1 + "," + sb2;
}
/**
*
* @methodDesc: 功能描述:(获取类的属性,拼接成字符串的值)
* @param: @return
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InstantiationException
*/
public static String getInsertDeclaredFieldsValue(Object oj) {
if (oj == null) {
return null;
}
Class cl = oj.getClass();
// 获取所有的属性
Field[] declaredFields = cl.getDeclaredFields();
String sb1 = appendFieldValues(declaredFields, oj);
Class superclass = cl.getSuperclass();
Field[] superField = superclass.getDeclaredFields();
String sb2 = appendFieldValues(superField, oj);
return sb1 + "," + sb2;
}
/**
*
* @methodDesc: 功能描述:(获取类的属性,拼接成字符串值)
* @param: @param
* oj
* @param: @return
*/
public static String updateAllSerField(Object oj) {
if (oj == null) {
return null;
}
Class cl = oj.getClass();
// 获取所有的属性
Field[] declaredFields = cl.getDeclaredFields();
String sb1 = updateSerField(declaredFields, oj);
Field[] supDeclaredFields = cl.getSuperclass().getDeclaredFields();
String sb2 = updateSerField(supDeclaredFields, oj);
return sb1 + "," + sb2;
}
public static String updateSerField(Field[] declaredFields, Object oj) {
StringBuffer sb = new StringBuffer();
try {
for (int i = 0; i < declaredFields.length; i++) {
String name = declaredFields[i].getName();
if (name.equals("id")) {
continue;
}
declaredFields[i].setAccessible(true);
Object value = declaredFields[i].get(oj);
if (value == null) {
continue;
}
sb.append(name + "=" + "'" + value + "'");
if ((i < declaredFields.length - 1)) {
sb.append(",");
}
}
} catch (Exception e) {
log.error("###updateSerField() ERROR:", e);
}
return sb.toString();
}
public static String appendFieldValues(Field[] declaredFields, Object oj) {
StringBuffer sf = new StringBuffer();
try {
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
String name = field.getName();
if (name == "id") {
continue;
}
field.setAccessible(true);// 设置私有权限访问
sf.append("'" + field.get(oj) + "'");
if (i < declaredFields.length - 1) {
sf.append(",");
}
}
} catch (Exception e) {
log.error("###ERROR:getDeclaredFieldsValue方法出现异常:", e);
}
return sf.toString();
}
public static String appendFields(Field[] declaredFields) {
StringBuffer sf = new StringBuffer();
// 获取到子类的
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
String name = field.getName();
if (name == "id") {
continue;
}
sf.append(field.getName());
if (i < declaredFields.length - 1) {
sf.append(",");
}
}
return sf.toString();
}
}