微服务电商系统(1)

项目介绍

微信商城+微信公众号开发,该项目根据上海某大型知名电商企业互联网互联网项目,改版而来,使用最新微服务技术,页面使用高仿小米界面。功能包含电商模块,会员、SSO、订单、商品、支付、消息、微信、H5和PC、移动端、优惠券、后台系统、任务调度等模块。

电商系统特点

1.技术新

2.技术范围广

3.分布式

4.高并发、集群、负载均衡、高并发

5.海量数据

6.业务复杂

7.系统安全

电商系统架构

微服务电商系统(1)

项目演变过程

传统架构

 微服务电商系统(1)

分布式架构 

微服务电商系统(1)

什么是分布式?

根据业务需求进行拆分成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

微服务电商系统(1)

环境搭建

 

环境搭建步骤

创建项目

引入依赖

搭建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作用

使用注解版本,生成getset方法、简化重复代码

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();
	}

}

上一篇:链表OJ题(一)


下一篇:牛客网oj输入输出总结