你好,我是田哥。前几天,有几位朋友私信我,叫我写一个使用Spring Cloud Alibaba 搭建项目。
今天,我给安排上,使用Spring Cloud Alibaba 搭建一个用户中心。
下面,我就来给大家说一下,我饿还是如何搭建的,具体步骤如下:
- 使用IDEA创建项目结构
- 添加maven相关依赖
- 安装
Nacos
- 业务代码
整个技术栈:
Spring Boo
t+Dubbo
+Nacos
+MyBatis
+MySQL
创建项目结构
我们先来创建父项目user-center,打开IDEA,进入File菜单。
然后,选择next
如果你的ArtifactId太长了,其中很多单词使用-
分割,那在这里最好把你的复制一遍,后面有用。
选择好自己的maven和本地仓库配置文件setting.xml
。
点击finish,那么一个简单的项目就创建了。
下面我们来创建modules
和前面一样
这里我们需要填写自己的module名称,比如:user-web或者user-service或者 user-api
然后就是next、next、最后就是finish(注意项目名称使用-
的情况,和尚庙创建父项目一样)。
同理,我们可以通过上面的方法创建对应的module。
注意:我们的父项目user-center不做任何业务相关,所以,我们需要把父项目user-center中的src目录
给删除。
然后,整个项目就变成了:
添加maven依赖
我们使用父项目进行版本管理,即user-center中的pom.xml内容如下:
<?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>
<packaging>pom</packaging>
<modules>
<module>user-web</module>
<module>user-service</module>
<module>user-api</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
</parent>
<groupId>com.tian</groupId>
<artifactId>user-center</artifactId>
<version>1.0-SNAPSHOT</version>
<name>user-center</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring-boot.version>2.3.0.RELEASE</spring-boot.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
user-api主要给服务消费者和服务提供者共同使用那部分代码,也就是提供给外部的api和相关共用代码。
user-api中pom.xml
内容:
<?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>
<parent>
<groupId>com.tian</groupId>
<artifactId>user-center</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>user-api</artifactId>
<version>1.0-SNAPSHOT</version>
<name>user-api</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
user-service是业务具体实现
user-service中pom.xml
内容:
<?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>
<parent>
<groupId>com.tian</groupId>
<artifactId>user-center</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>user-service</artifactId>
<version>1.0-SNAPSHOT</version>
<name>user-service</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.59</version>
</dependency>
<!-- 把user-api引进来-->
<dependency>
<groupId>com.tian</groupId>
<artifactId>user-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
</dependencies>
</project>
user-web是用户管理的页面系统
user-web中的pom.xml
内容:
<?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>
<parent>
<groupId>com.tian</groupId>
<artifactId>user-center</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>user-web</artifactId>
<version>1.0-SNAPSHOT</version>
<name>user-web</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<dependency>
<groupId>com.tian</groupId>
<artifactId>user-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
以上就是整个项目的整体结构。
user-center
|--user-api
|--user-service
|--user-web
项目整体结构以及搭建完成,我们现在把Nacos server端给搞定。
Nacos 安装
Nacos官网地址:https://nacos.io/
Nacos源码地址:https://github.com/alibaba/nacos
进入https://github.com/alibaba/nacos/releases
直接选择对应下载包接口:
下载下来,然后解压,建议配置成咱们自己的数据库,比如MySQL数据库。在\conf
目录下
在application.properties
配置文件中。
另外,一定要记得,创建数据库,在此数据库下执行脚本:nacos-mysql.sql
最后数据库中的表,有如下:
在 Linux/Unix/Mac 操作系统中使用下面命令启动Nacos(单机模式),找到Nacos的bin目录下:
sh startup.sh -m standalone
注意:必须安装有JVM,因为nacos是Java 开发的产品。
在Windows 操作系统中,打开CMD,来到Nacos的bin目录下:
startup.cmd -m standalone
快速开始,请参官方文档,中文版请求地址:
https://nacos.io/zh-cn/docs/quick-start.html
项目启动后,我们直接访问:
如果需要输入用户名和密码,则世界输入nacos/nacos
这里有数据,是因为我的服务已经注册上去了。
这里的配置管理 表示 nacos作为配置中心的相关管理。服务管理 便是我们的服务注册信息管理,其他这里不做讨论。
本文中,nacos所处位置:
业务代码
本文的重点在于构建项目基础架构,所以,本文中不会展示过多的业务代码。
user-api
这个module主要是服务提供者和服务消费者共同使用的代码,通常包括:service接口、数据传输对象DTO、一些工具类。
我们定义一类service接口类:
public interface UserService {
UserInfoDTO findUserInfoById(Long id);
UserInfoDTO findUserInfo(String userName, String password);
}
一个数据传输对象(注意需要实现Serializable用作序列化):
public class UserInfoDTO implements Serializable {
private Long id;
private String userName;
private Integer age;
private Integer gender;
private String phone;
// 省略 get set
}
user-service
也叫user-provider,就这个意思,懂了就行,另外,在项目开发中,遵循项目开发命名规范来就行。这个module里才是我们真正的业务处理,还有就是数据库操作也基本上在这里面。
下面我把代码都贴一遍。
application.properties
配置文件:
server.port=9002
spring.application.name=user-service
# dubbo 服务扫描基础包路径
dubbo.scan.base-packages=com.tian
dubbo.protocol.id=dubbo
# Dubbo 服务暴露的协议配置,其中子属性 name 为协议名称,port 为协议端口( -1 表示自增端口,从 20880 开始)
dubbo.protocol.name=dubbo
dubbo.protocol.port=28801
spring.cloud.nacos.discovery.server-addr=localhost:8848
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/user-center?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
mybatis.mapper-locations=classpath:mapper/**/*.xml
mybatis.type-aliases-package=com.tian.entity
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
UserServiceApplication
项目启动类:
@SpringBootApplication
@MapperScan("com.tian.mapper")
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
数据库表对应的实体类:
public class User {
private Long id;
private String userName;
private String password;
private Integer age;
private Integer gender;
private String phone;
//省略 set get
}
mapper接口类和xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.tian.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.tian.entity.User">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="password" property="password" jdbcType="VARCHAR"/>
<result column="age" property="age" jdbcType="INTEGER"/>
<result column="gender" property="gender" jdbcType="INTEGER"/>
<result column="phone" property="phone" jdbcType="VARCHAR"/>
</resultMap>
<sql id="BaseSQL">
id,user_name,age,gender,phone
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="long">
select
<include refid="BaseSQL"/>
from t_user where id=#{id}
</select>
<select id="findUserInfo" resultMap="BaseResultMap">
select
<include refid="BaseSQL"/>
from t_user where user_name =#{userName} and password=#{password}
</select>
</mapper>
public interface UserMapper {
User selectByPrimaryKey(Long uId);
User findUserInfo(@Param("userName") String userName, @Param("password") String password);
}
业务具体实现类(注意:这里的Service注解是dubbo中,不是spring中的):
@Service(protocol = "dubbo")
public class UserServiceImpl implements UserService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private UserMapper userMapper;
@Override
public UserInfoDTO findUserInfoById(Long id) {
logger.info("通过id查询用户信息,id={}", id);
User user = userMapper.selectByPrimaryKey(id);
if (user == null) {
logger.info("用户信息不存在,id={}", id);
return null;
}
UserInfoDTO userInfoDTO = new UserInfoDTO();
try {
BeanUtils.copyProperties(userInfoDTO, user);
} catch (Exception ex) {
logger.error("bean 转换失败", ex);
}
return userInfoDTO;
}
@Override
public UserInfoDTO findUserInfo(String userName, String password) {
User user = userMapper.findUserInfo(userName, password);
if(user == null){
return null;
}
UserInfoDTO userInfoDTO = new UserInfoDTO();
try {
BeanUtils.copyProperties(userInfoDTO, user);
} catch (Exception ex) {
logger.error("bean 转换失败", ex);
}
return userInfoDTO;
}
}
user-web
为了演示nacos作为分布式配置,所以,这个项目中的配置文件有所不同。
bootstrap.properties
配置文件:
spring.application.name=user-web
spring.cloud.nacos.config.server-addr=localhost:8848
spring.cloud.nacos.config.file-extension=properties
UserController
类:
@RestController
@RequestMapping("/user")
@RefreshScope//只需要在需要动态读取配置的类上添加此注解就可以使用@Value注解获取配置项
public class UserController {
@Resource
private IUserInfoService userInfoService;
/**
* nacos 作为配置中心 验证
*/
@Value("${config.test}")
private String configName;
@GetMapping("/info/{id}")
public ResultData findUserInfoById(@PathVariable("id") Long id) {
//输出我们在nacos配置中心配置的内容
System.out.println(configName);
return userInfoService.findUserInfoById(id);
}
@PostMapping(value = "/login")
public ResultData login(@RequestParam("userName") String userName,
@RequestParam("password") String password) {
if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)) {
return ResultData.fail(ResultCodeEnum.PARAM_EMPTY.getCode(), ResultCodeEnum.PARAM_EMPTY.getMsg());
}
return userInfoService.login(userName, password);
}
}
在user-web中,我们通常也会定义一个service目录,可以做一些数据包装转换之类的。
public interface IUserInfoService {
/**
* 查询用户信息
*/
ResultData findUserInfoById(Long id);
/**
* 用户登录
*/
ResultData login(String userName, String password);
}
实现类(注意:@Reference这个注解是Dubbo中的,protocol指定协议):
@Service
public class UserInfoServiceImpl implements IUserInfoService {
@Reference(protocol = "dubbo")
private UserService userService;
@Override
public ResultData findUserInfoById(Long id) {
UserInfoDTO userInfoDTO = userService.findUserInfoById(id);
if (userInfoDTO == null) {
return ResultData.fail(ResultCodeEnum.SYSTEM_ERROR.getCode(), ResultCodeEnum.SYSTEM_ERROR.getMsg());
}
return ResultData.success(userInfoDTO);
}
@Override
public ResultData login(String userName, String password) {
UserInfoDTO userInfoDTO =userService.findUserInfo(userName, password);
if (userInfoDTO == null) {
return ResultData.fail(ResultCodeEnum.LOGIN_FAILD.getCode(), ResultCodeEnum.LOGIN_FAILD.getMsg());
}
return ResultData.success(userInfoDTO);
}
}
项目启动类:
@SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
ResultData
返回数据类:
public class ResultData<T> {
private T data;
private int code;
private String msg;
public static <T> ResultData<T> success(T data) {
return new ResultData(data, ResultCodeEnum.LOGIN_SUCCESS.getCode(), ResultCodeEnum.LOGIN_SUCCESS.getMsg());
}
public static <T> ResultData<T> fail(int code, String errorMsg) {
return new ResultData(null, code, errorMsg);
}
}
ResultCodeEnum
返回码类:
public enum ResultCodeEnum {
SUCCESS(200, "操作成功"),
SYSTEM_ERROR(500, "系统错误"),
PARAM_EMPTY(400, "参数为空"),
LOGIN_SUCCESS(200, "登录成功"),
LOGIN_FAILD(500, "登录失败");
private int code;
private String msg;
//省略 相关非核心代码
}
好了,以上就是构建一个用户中心的主要代码,大家也可以在此基础之上,进行添加一些功能。同时还可以添加请求和相应参数的打印,也可以做一个统一异常处理。
后记
通过文中的方法,我们同样可以构建商品中心、订单中心,这样不就可以简单的构建一个电商项目了么?
好了,今天就分享到这里~