博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天

第1章 SAAS-HRM系统概述与搭建环境

最后附上视频下载地址

第一章第一天学习的地址:https://blog.****.net/xxxshazi_201612027/article/details/108305961

学习目标:
理解SaaS的基本概念
了解SAAS-HRM的基本需求和开发方式
掌握Power Designer的用例图
完成SAAS-HRM父模块及公共模块的环境搭建
完成企业微服务中企业CRUD功能

4 工程搭建

4.4 构建公共子模块
4.4.1 构建公共子模块ihrm-common

博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天


4.4.2 创建返回结果实体类

(1)新建com.ihrm.common.entity包,包下创建类Result,用于控制器类返回结果
<version>2.12.4</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
package com.ihrm.common.entity;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
//非空数据不显示
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result {
private boolean success;//是否成功
private Integer code;// 返回码
private String message;//返回信息
private Object data;// 返回数据
public Result(ResultCode code) {
this.success = code.success;
this.code = code.code;
this.message = code.message;
}
public Result(ResultCode code,Object data) {
this.success = code.success;
this.code = code.code;

this.message = code.message;
this.data = data;
}
public Result(Integer code,String message,boolean success) {
this.code = code;
this.message = message;
this.success = success;
}
public static Result SUCCESS(){
return new Result(ResultCode.SUCCESS);
}
public static Result ERROR(){
return new Result(ResultCode.SERVER_ERROR);
}
public static Result FAIL(){
return new Result(ResultCode.FAIL);
}
}

(2)创建类PageResult ,用于返回分页结果
package com.ihrm.common.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult<T> {
private Long total;
private List<T> rows;
}

4.4.3 返回码定义类


public enum ResultCode {
SUCCESS(true,10000,"操作成功!"),
//---系统错误返回码-----
FAIL(false,10001,"操作失败"),
UNAUTHENTICATED(false,10002,"您还未登录"),
UNAUTHORISE(false,10003,"权限不足"),SERVER_ERROR(false,99999,"抱歉,系统繁忙,请稍后重试!");
//---用户操作返回码----
//---企业操作返回码----
//---权限操作返回码----
//---其他操作返回码----
//操作是否成功
boolean success;
//操作代码
int code;
//提示信息
String message;
ResultCode(boolean success,int code, String message){
this.success = success;
this.code = code;
this.message = message;
}
public boolean success() {
return success;
}
public int code() {
return code;
}
public String message() {
return message;
}
}


4.4.4 分布式ID生成器


目前微服务架构盛行,在分布式系统中的操作中都会有一些全局性ID的需求,所以我们不能使用数据库本身的自增
功能来产生主键值,只能由程序来生成唯一的主键值。我们采用的是开源的twitter( 非官方中文惯称:推特.是国外
的一个网站,是一个社交网络及微博客服务) 的snowflake (雪花)算法。

博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天

各个段解析:

博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天

默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持1024台机器,***
支持1毫秒产生4096个自增序列id . SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内
不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID
左右
//雪花算法代码实现
public class IdWorker {
// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位
private final static long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits + workerIdBits +
datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0,并发控制
private long sequence = 0L;
private final long workerId;
// 数据标识id部分
private final long datacenterId;
public IdWorker(){
this.datacenterId = getDatacenterId(maxDatacenterId);

this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* @param workerId
* 工作机器ID
* @param datacenterId
* ***
*/
public IdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be
greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be
greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing
to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/*
* GET jvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
* MAC + PID 的 hashcode 获取16个低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
/**
* <p>
* 数据标识id部分
* </p>
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " + e.getMessage());
}
return id;}}

 

4.5 搭建公共的实体类模块

(1)构建公共子模块ihrm_common_model

博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天
(2)引入坐标

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.ihrm</groupId>
<artifactId>ihrm_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>


5 企业微服务-企业CRUD


5.1 模块搭建

(1)搭建企业微服务模块ihrm_company, pom.xml引入依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.ihrm</groupId>
<artifactId>ihrm_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
(2)添加配置文件application.yml

server:
port: 9001
spring:
application:
name: ihrm-company #指定服务名
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ihrm?useUnicode=true&characterEncoding=utf8
username: root
password: 111111
jpa:
database: MySQL
show-sql: true
open-in-view: true
}
}

(3)配置启动类

@SpringBootApplication(scanBasePackages = "com.ihrm")
@EntityScan("com.ihrm")
public class CompanyApplication {
public static void main(String[] args) {
SpringApplication.run(CompanyApplication.class, args);
}
@Bean
public IdWorker idWorkker() {
return new IdWorker(1, 1);
}
}

5.2 企业管理-CRUD


5.2.1 表结构分析

CREATE TABLE `co_company` (
`id` varchar(40) NOT NULL COMMENT 'ID',
`name` varchar(255) NOT NULL COMMENT '公司名称',
`manager_id` varchar(255) NOT NULL COMMENT '企业登录账号ID',
`version` varchar(255) DEFAULT NULL COMMENT '当前版本',
`renewal_date` datetime DEFAULT NULL COMMENT '续期时间',
`expiration_date` datetime DEFAULT NULL COMMENT '到期时间',
`company_area` varchar(255) DEFAULT NULL COMMENT '公司地区',
`company_address` text COMMENT '公司地址',
`business_license_id` varchar(255) DEFAULT NULL COMMENT '营业执照-图片ID',
`legal_representative` varchar(255) DEFAULT NULL COMMENT '法人代表',
`company_phone` varchar(255) DEFAULT NULL COMMENT '公司电话',
`mailbox` varchar(255) DEFAULT NULL COMMENT '邮箱',
`company_size` varchar(255) DEFAULT NULL COMMENT '公司规模',
`industry` varchar(255) DEFAULT NULL COMMENT '所属行业',
`remarks` text COMMENT '备注',

`audit_state` varchar(255) DEFAULT NULL COMMENT '审核状态',
`state` tinyint(2) NOT NULL DEFAULT '1' COMMENT '状态',
`balance` double NOT NULL COMMENT '当前余额',
`create_time` datetime NOT NULL COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

5.2.2 完成企业增删改查操作


(1)实体类(domain)

@Entity
@Table(name = "co_company")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Company implements Serializable {
private static final long serialVersionUID = 594829320797158219L;
//ID
@Id
private String id;
/**
* 公司名称
*/
private String name;
/**
* 企业登录账号ID
*/
private String managerId;
/**
* 当前版本
*/
private String version;
/**
* 续期时间
*/
private Date renewalDate;
/**
* 到期时间
*/
private Date expirationDate;
/**
* 公司地区
*/
private String companyArea;
/**
* 公司地址
*/
private String companyAddress;
/**
* 营业执照-图片ID
*/
private String businessLicenseId;
/**

* 法人代表
*/
private String legalRepresentative;
/**
* 公司电话
*/
private String companyPhone;
/**
* 邮箱
*/
private String mailbox;
/**
* 公司规模
*/
private String companySize;
/**
* 所属行业
*/
private String industry;
/**
* 备注
*/
private String remarks;
/**
* 审核状态
*/
private String auditState;
/**
* 状态
*/
private Integer state;
/**
* 当前余额
*/
private Double balance;
/**
* 创建时间
*/
private Date createTime;

}

(2)持久层(dao)

/**
* 企业数据访问接口
*/
public interface CompanyDao extends JpaRepository<Company, String>,
JpaSpecificationExecutor<Company> {
}

JpaRepository提供了基本的增删改查 JpaSpecificationExecutor用于做复杂的条件查询
(3)业务逻辑层(service)

@Service
public class CompanyService {
@Autowired
private CompanyDao companyDao;
@Autowired
private IdWorker idWorker;
/**
* 添加企业
*
* @param company 企业信息
*/
public Company add(Company company) {
company.setId(idWorker.nextId() + "");
company.setCreateTime(new Date());
company.setState(1); //启用
company.setAuditState("0"); //待审核
company.setBalance(0d);
return companyDao.save(company);
}
public Company update(Company company) {
return companyDao.save(company);
}
public Company findById(String id) {
return companyDao.findById(id).get();
}
public void deleteById(String id) {
companyDao.deleteById(id);
}
public List<Company> findAll() {
return companyDao.findAll();
}
}

(4)控制器

@RestController
@RequestMapping("/company")
public class CompanyController{
@Autowired
private CompanyService companyService;
/**
* 添加企业
*/
@RequestMapping(value = "", method = RequestMethod.POST)
public Result add(@RequestBody Company company) throws Exception {
companyService.add(company);

return Result.SUCCESS();
}
/**
* 根据id更新企业信息
*/
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public Result update(@PathVariable(name = "id") String id, @RequestBody Company
company) throws Exception {
Company one = companyService.findById(id);
one.setName(company.getName());
one.setRemarks(company.getRemarks());
one.setState(company.getState());
one.setAuditState(company.getAuditState());
companyService.update(company);
return Result.SUCCESS();
}
/**
* 根据id删除企业信息
*/
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public Result delete(@PathVariable(name = "id") String id) throws Exception {
companyService.deleteById(id);
return Result.SUCCESS();
}
/**
* 根据ID获取公司信息
*/
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Result findById(@PathVariable(name = "id") String id) throws Exception {
Company company = companyService.findById(id);
return new Result(ResultCode.SUCCESS);
}
/**
* 获取企业列表
*/
@RequestMapping(value = "", method = RequestMethod.GET)
public Result findAll() throws Exception {
List<Company> companyList = companyService.findAll();
return new Result(ResultCode.SUCCESS);
}
}

5.2.3 测试


(1) 测试工具postman
Postman提供功能强大的Web API & HTTP 请求调试。软件功能非常强大,界面简洁明晰、操作方便快捷,设计得
很人性化,

能够发送任何类型的HTTP 请求 (GET, HEAD, POST, PUT..),附带任何数量的参数。

使用资料中提供的postman安装包进行安装,注册成功之后即可使用
(2) 使用postman测试企业接口

博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天

5.3 公共异常处理
为了使我们的代码更容易维护,同时给用户最好的用户体验,有必要对系统中可能出现的异常进行处理。spring提供
了@ControllerAdvice注解和@ExceptionHandler可以很好的在控制层对异常进行统一处理
(1)添加自定义的异常

package com.ihrm.common.exception;
import com.ihrm.common.entity.ResultCode;
import lombok.Getter;
@Getter
public class CommonException extends RuntimeException {
private static final long serialVersionUID = 1L;
private ResultCode code = ResultCode.SERVER_ERROR;
public CommonException(){}
public CommonException(ResultCode resultCode) {
super(resultCode.message());
this.code = resultCode;
}
}

 

(2)配置公共异常处理

package com.ihrm.common.exception;
import com.alibaba.fastjson.JSON;
import com.ihrm.common.entity.Result;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 全局异常处理
*/
@ControllerAdvice
public class BaseExceptionHandler {
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Result error(HttpServletRequest request, HttpServletResponse response,
Exception e) throws IOException {
e.printStackTrace();
if (e.getClass() == CommonException.class) {
CommonException ce = (CommonException) e;
return new Result(ce.getCode());
} else {
return Result.ERROR();
}
}
}

5.4 跨域处理


跨域是什么?浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域 。我
们是采用前后端分离开发的,也是前后端分离部署的,必然会存在跨域问题。 怎么解决跨域?很简单,只需要在
controller类上添加注解@CrossOrigin 即可!这个注解其实是CORS的实现。 CORS(Cross-Origin Resource
Sharing, 跨源资源共享)是W3C出的一个标准,其思想是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而
决定请求或响应是应该成功,还是应该失败。因此,要想实现CORS进行跨域,需要服务器进行一些设置,同时前
端也需要做一些配置和分析。本文简单的对服务端的配置和前端的一些设置进行分析。

第一章到此结束!!!

博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天

博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天

博学谷-基于SaaS平台的iHRM实战开发 SAAS-HRM系统概述与搭建环境第二天

https://www.boxuegu.com/promote/detail-1232.html

基于SaaS平台的iHRM实战开发

百度网盘下载链接:
链接: https://pan.baidu.com/s/1repa2B4XYycXNK4pO8QyAw  密码: vl27

如果失效联系v信:itit11223344