一、概述
该项目前后端分离,要用到很多个框架与容器的,所以有一定的难度。
首先太多概念的东西不懂,先不说了。
首先因为是微服务化,把每个业务都拆分成很多个小块,每一个小块都是一个微服务,比如这个微服务是MYSQL,那这微服务是发博客的个人定义API。
要做到微服务,就要模仿把东西都放在网络上的,所以,我们连接MYSQL不再是127.0.0.1了,而是通过之前所学的docker下载MYSQL,再通过软件连接docker中的地址mysql进行操作。
二、docker创建mysql微服务
VMware16序列号:ZF3R0-FHED2-M80TY-8QYGC-NPKYF
下载VMware16、Xshell、已经安装好的Linux系统。
1、虚拟机安装+Linux虚拟机
VMware16中加载虚拟机(该虚拟机已经安装好镜像了)
Linux账号:root,密码:itcast
得到虚拟机IP地址
2、xshell+xftp安装
都在文件里面,都是点卸载再绿化,xftp可以进行win与Linux交互
在XShell中新建,因为在虚拟机中,运行操作很不方便,这个是用来辅助那个虚拟机的工具
3、启动docker
5、开机启动docker
systemctl enable docker
systemctl start docker
docker的知识在之前已经说过去一些了
4、启动mysql
docker run -di --name=tensquare_mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root centos/mysql-57-centos7
--name
:取名字-p 3306:3306
:虚拟机端口号,映射到真实的端口号,一般取一样就行-e MYSQL_ROOT_PASSWORD=root
:账号默认root,密码自定义为root- 最后面的,就是用到什么容器的
下次开机再运行容器,就docker start 容器id
这样子,就成功了
为什么要花这么大的东西去连接数据库,连接本地数据库就行了?
因为我们要做的分布式spring cloud,把每个东西拆分出来放到镜像中,而那个虚拟机一般是我们项目中的网络服务器的,现在没钱买服务器嘛,但是总是要练习的,所以就假设这个虚拟机时网络服务器的。然后那个网络服务器就有个docker,就是容器管理的东西。
最后,关机时把虚拟机停止,不要关虚拟机
三、构造父工程
就新创建一个工程而已嘛,我们要的只是maven中的pom文件,其他微服务的东西再在父工程里面拆分。然后导入的maven就是公共的maven了
<?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>org.example</groupId>
<artifactId>tensquare</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>tensquare_parent</name>
<description>毕业设计:十次方项目</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.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>
</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.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
四、导入数据库
数据库和下面的nginx和前后端约定的接口,都没有说,都说到后面有说。所以我也不知道表和表之的结构是什么,导入了。。。
五、 nginx与搭建公共值对象/包
1、nginx
nginx是一个很神奇的东西,可以快速地构造前后端之间的接口交互的数据约定
,就是前端给后台respond的JSON数据,后台给前端的request的JSON数据,用页面的形式给我们展示交接的数据结构
但由于教程与能力的有限,不知道这个怎么做出来的(其项目组本来就做好了,我直接拿来用),教程说看到前端会教的。。
直接解压到没有特殊和中文符号的目录下,双击nginx.exe,然后CMD一闪而过
http://localhost:801/
可以看到,发出去的请求(request)给前端的数据结构都是多种多样的,但是前端给后台(respond)的格式都是
boolea flag;
Interger code;
String message;
Object data;
其中,data用Object的原因是,有些data是List
有些是数组
有些是单单一个对象
2、创建公共模块返回值对象
在父目录下创建一个maven工程,在父工程,new一个Module
根据上面的前后端约定,返回值对象都是差不多的,就创建一个对象。
(1)通用结果对象
@Data
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;
}
public Result(boolean flag, Integer code, String message, Object data) {
this.flag = flag;
this.code = code;
this.message = message;
this.data = data;
}
}
(2)分页查询结果类
//分页查询结果类
@Data
public class PageResult<T> {
private Integer total;
private List<T> rows;
public PageResult(Integer total, List<T> rows) {
this.total = total;
this.rows = rows;
}
}
(3)状态码
package entity;
//状态码
public class StatusCode {
public static final int OK=20000;//成功
public static final int ERROR =20001;//失败
public static final int LOGINERROR =20002;//用户名或密码错误
public static final int ACCESSERROR =20003;//权限不足
public static final int REMOTEERROR =20004;//远程调用失败
public static final int REPERROR =20005;//重复操作
}
(4)util下的ID生成器
开源的,直接导入就行
六、创建base模块
这是完成的样子
1、POM
就继续创建一个maven,POM文件:
<?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</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>tensquare_commom</artifactId>
</project>
这个就很原生啥都没有,就上maven仓库中要加什么,就放什么
(学到后面发现不如之间new model时候创建spring工程。。。)
我们要用到Spring Boot Starter Data JPA、mysql-connector-java和之前的common
前两个直接上maven仓库找,common就alt+insert
,弹出来搜索
<?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</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>tensquare_base</artifactId>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>tensquare_commom</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
2、yml
server:
port: 9001
spring:
application:
# 微服务通过application-name来进行连接,不能用_
name: tensquare-base
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.12.128/tensquare_base?characterEncoding=UTF-8
username: root
password: root
jpa:
database: mysql
show-sql: true
3、根据前后端接口创建controller
(1)、微服务概念
先说下微服务化,就是现在是tensquare_base,这是一个spring项目,端口为9001,有独立的@SpringBootApplication,独立的数据库,独立的DAO、controller、service层的东西,是一个独立的spring项目。通过pom文件设置该项目是父项目的子项目,跨端口号进行数据交换的。所以,我们把tensquare_base停掉,也不会对其他模块造成影响,这就是微服务化。
(2)、看前端约定
我们先做增删改查
增:
可看到,增加的,传过来一个JSON,所以我们要把JSON转换成JAVA对象,对象设为Label
之前导入的,有个tensquare_base数据库,里面有个tb_label表,专门存储这些数据的,JPA嘛,就要把该表和对象都变成一样的结构
(3)、Label类与tb_label表
/*
@Entity,做JPA的pojo一定要加这个
@Table,和那个表对应
分布式一定要继承Serializable
*/
@Entity
@Table(name = "tb_label")
@Data
public class Label implements Serializable {
@Id
private String id;
private String labelname;//标签名称
private String state;//状态
private Long count;//使用数量
private Long fans;//关注数
private String recommend;//是否推荐
}
- 一般要返回到前端不规则的类,接口继承
Serializable
(4)、dao层与service层
因为是使用JPA,所以很简单
dao:
public interface LabelDao extends JpaRepository<Label,String>, JpaSpecificationExecutor<Label> {
}
Service:
@Service
@Transactional//保证数据库事务完整性
public class LabelService {
@Autowired
private LabelDao labelDao;
@Autowired
private IdWorker idWorker;
public List<Label> findAll(){
return labelDao.findAll();
}
public Label findById(String id){
return labelDao.findById(id).get();
}
public void save(Label label){
label.setId(idWorker.nextId()+"");
labelDao.save(label);
}
public void update(Label label){
labelDao.save(label);
}
public void deleteById(String id){
labelDao.deleteById(id);
}
}
(5)、controller
这一层不能乱写,前后端交接的是什么,就写什么
@RestController
@CrossOrigin
@RequestMapping("/label")//基础请求都是localhost:9001/label
public class LabelController {
@Autowired
private LabelService labelService;
//代码
}
①查询全部
没有传入参数,就要求传出是Result类的就行
@GetMapping("")
public Result findAll(){
return new Result(true, StatusCode.OK,"查询成功",labelService.findAll());
}
②根据ID查询
传入请求参数ID
@GetMapping("{labelId}")
public Result findById(@PathVariable("labelId") String labelId){
return new Result(true, StatusCode.OK,"查询成功",labelService.findById(labelId));
}
③增加数据
传入请求/
,body为一个JSON数据,但前面我们写好的转化好的对象Label
@PostMapping("")
public Result save(@RequestBody Label label){
labelService.save(label);
return new Result(true, StatusCode.OK,"添加成功");
}
④更新数据
请求为ID,body为Label类
@PutMapping("{labelId}")
public Result update(@RequestBody Label label,@PathVariable("labelId") String labelId){
label.setId(labelId);
labelService.update(label);
return new Result(true, StatusCode.OK,"更新成功");
}
⑤删除数据
请求为ID
@DeleteMapping("{labelId}")
public Result deleteById(@PathVariable("labelId") String labelId){
labelService.deleteById(labelId);
return new Result(true, StatusCode.OK,"删除成功");
}
(6)效果
(7)异常处理
比如我们自己弄一些错误
@GetMapping("")
public Result findAll(){
int i = 1/0;
return new Result(true, StatusCode.OK,"查询成功",labelService.findAll());
}
得到错误是
但是我们看前后端约定的接口
要求是Result类的JSON格式,这个很明显不对,这时候就要转化了
//@RestControllerAdvice是增强型的检测异常
@RestControllerAdvice
public class BaseExceptionHandler {
@ExceptionHandler(Exception.class)
public Result exception(Exception e){
e.printStackTrace();
return new Result(false, StatusCode.ERROR,e.getMessage());
}
}
@RestControllerAdvice、@ExceptionHandler
这个异常可以进行全局异常处理,常常和@ExceptionHandler配合使用,详情看
https://www.cnblogs.com/lenve/p/10748453.html
七、到目前的总结
给我的感觉,就是得先确认要用什么技术,写好文档再做下一步。
然后就是分微服务化,做好每个微服务要做什么东西。
接下来就是我个人认为最重要得一步,就是写好前后端的接口,互相交互的数据格式是什么,写好了通用的,才能确定前端给后端返回的pojo,后端给前端的JSON数据,才能建立数据库。DAO层和service层都是次要,如果一开始的规定格式不写好,会造成pojo过多,controller不知道返回什么数据,保存到数据库是什么数据。
教程已经弄好了,数据库和前后端交互帮我们弄好,我们就只要根据前后端接口弄POJO和Result类,返回给前端。前端给什么请求什么body,传对象给后端保存到数据库中