十次方项目搭建、系统介绍和基础微服务搭建
《十次方》是程序员的专属社交平台,包括头条、问答、活动、交友、吐槽、招聘六大
频道。
系统设计
《十次方》采用前后端分离的系统架构,后端架构为:
SpringBoot+SpringCloud+SpringMVC+SpringData 我们把这种架构也称之为全家桶。
模块划分
十次方工程共分为18个子模块(其中17个是微服务)
模块名称 |
模块中文名称 |
tensquare_common |
公共模块 |
tensquare_article |
文章微服务 |
tensquare_base |
基础微服务 |
tensquare_friend |
交友微服务 |
tensquare_gathering |
活动微服务 |
tensquare_qa |
问答微服务 |
tensquare_recruit |
招聘微服务 |
tensquare_user |
用户微服务 |
tensquare_spit |
吐槽微服务 |
tensquare_search |
搜索微服务 |
tensquare_web |
前台微服务网关 |
tensquare_manager |
后台微服务网关 |
tensquare_eureka |
注册中心 |
tensquare_config |
配置中心 |
tensquare_sms |
短信微服务 |
tensquare_article_crawler |
文章爬虫微服务 |
tensquare_user_crawler |
用户爬虫微服务 |
tensquare_ai |
人工智能微服务 |
后端状态码定义
状态描述 |
返回码 |
成功 |
20000 |
失败 |
20001 |
用户名密码错误 |
20002 |
权限不足 |
20003 |
远程调用失败 |
20004 |
重复操作 |
20005 |
项目准备
VMware Workstation Pro
CentOS 7镜像
安装CentOS 7(省略)
CentOS 7安装docker
安装docker
需要保证你的CentOS 7
能够连接到互联网,可以在虚拟机中使用ping
命令。
通过 uname -r 命令查看你当前的内核版本
移除旧的版本docker
1 2 3 4 5 6 7 8 9 10
| yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine
|
安装依赖
1
| yum install -y yum-utils device-mapper-persistent-data lvm2
|
增加yum
源
1
| yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
|
更新yum
缓存
安装 Docker-ce
,ce
为社区版,ee
为企业版,但是要收费🤦
1
| yum -y install docker-ce
|
启动 Docker
后台服务
查看是否安装成功
安装MySQL镜像
搜索mysql
镜像
拉取mysql
镜像
1 2 3
| # 这里拉取centos提供的mysql镜像,这个过程可能会非常的缓慢 # 实在不行就用人家提供好的centos镜像吧 docker pull centos/mysql‐57‐centos7
|
CentOS提供的镜像集合:docker hub
会介绍每一个容器的使用方法,建议浏览,但是是英文的(右键 -> 谷歌翻译 o( ̄▽ ̄)d)。
运行mysql
镜像
1 2 3 4
| # 查看本地镜像 docker images # 安装mysql镜像 docker run ‐di ‐‐name=tensquare_mysql ‐p 3306:3306 ‐e MYSQL_ROOT_PASSWORD=123456 centos/mysql‐57‐centos7
|
使用数据库界面工具
连接mysql
建库建表(省略)
项目搭建
父工程搭建
创建module
- GroupId:
com.tensquare
- ArtifactId:
tensquare_parent
pom.xml依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.tensquare</groupId> <artifactId>tensquare_parent</artifactId> <packaging>pom</packaging> <version>1.0.0-SNAPSHOT</version>
<description>十次方项目</description> <modules> <module>tensquare_common</module> </modules>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> <relativePath/> </parent>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <tensquare.version>1.0.0-SNAPSHOT</tensquare.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
<repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
<pluginRepositories> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </project>
|
公共模块搭建
创建module
- GroupId:
com.tensquare
- ArtifactId:
tensquare_common
实体类
通用返回结果实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package entity;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor public class Result {
private boolean flag;
private Integer code;
private String message;
private Object data;
public Result(boolean flag, Integer code, String message) { this.flag = flag; this.code = code; this.message = message; }
}
|
状态码枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package entity;
import lombok.Getter;
@Getter public enum StatusCode {
OK(20000, "请求成功"), ERROR(20001, "请求失败"), LOGIN_ERROR(20002, "用户名或密码错误"), ACCESS_ERROR(20003, "权限不足"), REMOTE_ERROR(20004, "远程调用失败"), REP_ERROR(20005, "重复操作"), ;
private int statusCode; private String defaultMessage;
StatusCode(int statusCode, String defaultMessage) { this.statusCode = statusCode; this.defaultMessage = defaultMessage; } }
|
分页结果实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package entity;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
import java.util.List;
@Data @NoArgsConstructor @AllArgsConstructor public class PageResult<T> {
private Long total; private List<T> rows;
}
|
ID生成工具类
由于我们的数据库在生产环境中要分片部署(MyCat),所以我们不能使用数据库本身的自增功能来产生主键值,只能由程序来生成唯一的主键值。
我们采用的是开源的twitter
( 非官方中文惯称:推特.是国外的一个网站,是一个社交网络及微博客服务) 的snowflake(雪花)
算法。
基础微服务(tensquare_base)
标签管理(CRUD)
表结构分析
字段名称 |
字段含义 |
字段类型 |
备注 |
id |
ID |
文本 |
|
labelname |
标签名称 |
文本 |
|
state |
状态 |
文本 |
0:无效 1:有效 |
count |
使用数量 |
整型 |
|
fans |
关注数 |
整型 |
|
recommend |
是否推荐 |
文本 |
0:不推荐1:推荐 |
准备工作
项目搭建
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>tensquare_parent</artifactId> <groupId>com.tensquare</groupId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
<artifactId>tensquare_base</artifactId>
<dependencies> <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.tensquare</groupId> <artifactId>tensquare_common</artifactId> <version>${tensquare.version}</version> </dependency> </dependencies>
</project>
|
启动类
1 2 3 4 5 6 7 8 9 10 11
| package com.tensquare;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class BaseApplication { public static void main(String[] args) { SpringApplication.run(BaseApplication.class, args); } }
|
application.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server: port: 9001 spring: application: name: tensquare-base datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.136.104:3306/tensquare_base?characterEncoding=utf8 username: root password: 123456 jpa: database: MySQL show‐sql: true generate‐ddl: true
|
实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package com.tensquare.base.entity;
import constants.ModelConstants; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table;
@Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name = ModelConstants.TABLE_LABEL) public class Label {
@Id private String id;
private String labelname;
private String state;
private Long count;
private String recommend;
private Long fans; }
|
这里我正在tensquare
中新建了ModelConstants
专门存放实体相关的一些常量,比如表名称,字段名称等
ModelConstants
如下:
1 2 3 4 5 6 7 8 9 10 11
| package constants;
public class ModelConstants {
public static final String TABLE_LABEL = "tb_label"; }
|
config
IdWorkerProperties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.tensquare.base.config;
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties;
@Data @ConfigurationProperties("tensquare.worker") public class IdWorkerProperties {
private Long workerId;
private Long datacenterId;
}
|
需要在application.yaml
中配置:
1 2 3 4
| tensquare: worker: workerId: 1 datacenterId: 1
|
IdWorkerConfiguration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.tensquare.base.config;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import util.IdWorker;
@Configuration @EnableConfigurationProperties(IdWorkerProperties.class) public class IdWorkerConfiguration {
@Autowired private IdWorkerProperties prop;
@Bean public IdWorker getIdWorker() { return new IdWorker(prop.getWorkerId(), prop.getDatacenterId()); }
}
|
controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| package com.tensquare.base.controller;
import com.tensquare.base.entity.Label; import com.tensquare.base.service.LabelService; import entity.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.Map;
@RestController @RequestMapping("label") public class LabelController {
@Autowired private LabelService labelService;
@PostMapping public Result insert(@RequestBody Label label) { labelService.save(label); return Result.ok("新增成功"); }
@GetMapping public Result queryLabels() { List<Label> labelList = labelService.findAll(); return Result.ok(labelList); }
@GetMapping("{labelId}") public Result queryById(@PathVariable("labelId") String id) { return Result.ok(labelService.findById(id)); }
@DeleteMapping("{labelId}") public Result remove(@PathVariable("labelId") String id) { labelService.deleteById(id); return Result.ok("删除成功"); }
@PutMapping("{labelId}") public Result update(@RequestBody Label label, @PathVariable("labelId") String id) { label.setId(id); labelService.update(label); return Result.ok("修改成功"); }
@PostMapping("/search/{page}/{size}") public Result queryByPage(@RequestBody Map searchMap, @PathVariable("page") int page, @PathVariable("size") int size) { return Result.ok(labelService.queryByPage(searchMap, page, size)); }
}
|
service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| package com.tensquare.base.service;
import com.tensquare.base.dao.LabelRepository; import com.tensquare.base.entity.Label; import entity.PageResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import util.IdWorker;
import javax.persistence.criteria.Predicate; import java.util.ArrayList; import java.util.List; import java.util.Map;
@Service public class LabelService {
@Autowired private LabelRepository labelRepository;
@Autowired private IdWorker idWorker;
public Label save(Label label) { label.setId(idWorker.nextId().toString()); return labelRepository.save(label); }
public List<Label> findAll() { return labelRepository.findAll(); }
public Label findById(String id) { return labelRepository.findById(id).get(); }
public void deleteById(String id) { labelRepository.deleteById(id); }
public void update(Label label) { labelRepository.save(label); }
public PageResult<Label> queryByPage(Map searchMap, int page, int size) { Specification<Label> specification = createSpecification(searchMap); Page<Label> labelPage = labelRepository.findAll(specification, PageRequest.of(page, size)); return new PageResult<>(labelPage.getTotalElements(), labelPage.getContent()); }
public List<Label> findAll(Map searchMap) { Specification<Label> specification = createSpecification(searchMap); return labelRepository.findAll(specification); }
private Specification<Label> createSpecification(Map searchMap) { String labelname = (String) searchMap.get("labelname"); String state = (String) searchMap.get("state"); String recommend = (String) searchMap.get("recommend"); return (Specification<Label>) (root, criteriaQuery, criteriaBuilder) -> { List<Predicate> predicateList = new ArrayList<>();
if (!StringUtils.isEmpty(labelname)) { predicateList.add(criteriaBuilder.like(root.get("labelname").as(String.class), "%" + labelname + "%")); } if (!StringUtils.isEmpty(state)) { predicateList.add(criteriaBuilder.equal(root.get("state").as(String.class), state)); } if (!StringUtils.isEmpty(recommend)) { predicateList.add(criteriaBuilder.equal(root.get("recommend").as(String.class), "%" + recommend + "%")); } return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()])); }; } }
|
dao
1 2 3 4 5 6 7 8
| package com.tensquare.base.dao;
import com.tensquare.base.entity.Label; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface LabelRepository extends JpaRepository<Label, String>, JpaSpecificationExecutor<Label> { }
|
统一异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.tensquare.base.exception;
import entity.Result; import entity.StatusCode; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j @RestControllerAdvice public class BaseExceptionHandler {
@ExceptionHandler(Exception.class) public Result error(Exception e) { log.error("[发生异常] ", e); return Result.error(StatusCode.ERROR.getStatusCode(), StatusCode.ERROR.getDefaultMessage()); }
}
|