微服務電商系統
電商系統架構
使用新技術介紹
專案環境搭建
工具類的封裝
專案介紹
微信商城+微信公眾號開發,該專案根據上海某大型知名電商企業網際網路網際網路專案,改版而來,使用最新微服務技術,頁面使用高仿小米介面。功能包含電商模組,會員、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授權等。
專案構建
itmayiedu-shopp-parent
├─itmayiedu-shopp-common // 抽取的公共模組
├─itmayiedu-shopp-eurekaserver // eureka註冊中心
├─itmayiedu-shopp-api // api服務
├─itmayiedu-shopp-member-api // 會員服務
├─itmayiedu-shopp-order-api // 訂單服務
├─itmayiedu-shopp-goods-api // 商品服務
├─itmayiedu-shopp-pay-api // 支付服務
├─itmayiedu-shopp-member // 會員系統
├─itmayiedu-shopp-nessage // 訊息系統
├─itmayiedu-shopp-mobile-web // h5端工程
建立Modules
環境搭建
環境搭建步驟
建立專案
引入依賴
搭建eureka註冊中心
封裝控制層、日誌、常量、常用工具、Basedao
itmayiedu-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>
itmayiedu-shopp-common
Maven依賴
<parent>
<groupId>com.itmayiedu</groupId>
<artifactId>itmayiedu-shopp-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>itmayiedu-shopp-common</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
itmayiedu-shopp-eurekaserver
Maven依賴
<parent>
<groupId>com.itmayiedu</groupId>
<artifactId>itmayiedu-shopp-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.itmayiedu</groupId>
<artifactId>itmayiedu-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/
itmayiedu-shopp-api
建立itmayiedu-shopp-api工程,存放所有的需要提供給外部介面項
目
itmayiedu-shopp-member-api
建立MemberService測試介面
@RequestMapping("/member")
public interface MemberService {
@RequestMapping("/testRest")
public Map<String, Object> testRest();
}
itmayiedu-shopp-member
Maven依賴
<dependencies>
<dependency>
<groupId>com.itmayiedu</groupId>
<artifactId>itmayiedu-shopp-member-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.itmayiedu</groupId>
<artifactId>itmayiedu-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的官方下載網址是:http://redis.io/download (這裡下載的是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
在itmayiedu-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.itmayiedu.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("--------------返回內容----------------");
}
}
日誌收集
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/itmayiedu-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)
*/
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反射工具類)
*/
@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();
}
}
程式碼測試