微服务: 简单的用户名注册和登录

内容概要

在本篇中我们要完成一个目标:提供注册、登录的接口给前端或者客户端来使用

涉及到的内容主要有下面几个:

1、SpringBoot 中常用的注解如何使用?

2、 如何对接口进行单元测试?

其他相关的微服务文章,可以点击 微服务项目系列文章 了解。

常用注解

控制器 Controller 是 Spring 中最基本的组件,主要是处理跟用户交互的,一般每个业务逻辑都会有一个 Controller,提供 HTTP 请求接口,用户请求接口进行数据访问。

跟 Controller 相关的几个注解主要有 @Controller@RestController@RequestMapping@PathVariable@RequestParam@GetMapping 等。

  • @Controller:标注 Controller 类,处理 HTTP 请求。
  • @RestController:标注 Controller 类,Spring 4 新加注解,相当于 @Controller + @ResponseBody ,主要是为了使 HTTP 请求返回数据格式为 json 格式,正常情况下都是使用这个注解。
  • @RequestMapping:配置 URL 映射,即请求的地址。
  • @PathVariable@RequestParam@QueryParam@PathParam 注解,可以参考 微服务: 学习几个容易混淆的URL注解 这篇文章。
  • @GetMapping@PostMapping@PutMapping 称之为组合注解,它们等价于 @RequestMapping 单独指定映射再指定请求方法。举个例子,如下:
1
@RequestMapping(value = "/signup/name", method = RequestMethod.POST)

等价于下面的注解:

1
@PostMapping(value = "/signup/name")

编写实体

不管是登录还是注册,都是每个用户进行的操作,我们先定义用户实体类 MSUser,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import lombok.Data;
import java.io.Serializable;
@Data
public class MSUser implements Serializable {
private String userID;
// 账号名称,用于登录,不可以修改
private String accountName;
// 账号密码
private String accountPwd;
// 昵称默认和accountName一致,可以修改
private String nickName;
private Integer age;
private Integer gender;
// 座右铭;格言;箴言
private String motto;
}

大家可以看到,在实体类 MSUser 中,我们用到了注解 @Data ,该注解来源于 lombok,需要自己在IDEA中安装该插件,安装方法请大家自行搜索解决。

注解 @Data 相当于给我们自动实现了 GetSettertoStringequalshashCode 方法以及构造方法,不需要我们自己再去写这些代码。

HTTP 的请求响应结果,也可以被封装为实体类,如下 MSResponse 就是用来承载HTTP返回的响应。

1
2
3
4
5
6
7
8
import lombok.Data;
@Data
public class MSResponse<T> {
private int code;
private String msg;
private T results;
}

编写接口

一般来说,用户注册需要将用户的信息存下来,存到数据库中方便后续使用这份数据,这个行为称之为 数据持久化 ,现在我们不做这个操作,只是纯粹的提供接口让用户可以注册、登录我们的系统,后续再来考虑和实现数据持久化。

这个阶段注册功能只提供 用户名+密码 的方式,该请求是个 POST 请求,主要核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RestController
@RequestMapping(value = "signup")
public class MSSignupController {
@CrossOrigin(origins = {"*"})
@PostMapping(value = "/name")
public MSResponse signup(@RequestParam(value = "username") String userName, @RequestParam(value = "userpwd") String userPwd) {
MSResponse response = new MSResponse();
MSUser user = null;
if (null == userName || null == userPwd || userName.length() <= 0 || userPwd.length() <= 0) {
MSResponseEnum signupError = MSResponseEnum.SignupInvalidInfo;
response.setMsg(signupError.getMsg());
response.setCode(signupError.getCode());
} else {
response.setCode(MSResponseEnum.SUCCESS.getCode());
response.setMsg(MSResponseEnum.SUCCESS.getMsg());
user = MSUserUtil.createUser(userName, userPwd);
}
response.setResults(user);
return response;
}
}

同理,登录功能也只提供 用户名+密码 的方式,该请求是个 GET 请求,主要核心代码如下:

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
@RestController
@RequestMapping(value = "signin")
public class MSSigninController {
@CrossOrigin(origins = {"*", "http://localhost:8082"})
@RequestMapping(value = "/name", method = RequestMethod.GET)
public MSResponse sigin(@RequestParam(value = "username") String userName, @RequestParam(value = "userpwd") String userPwd) {
MSResponse response = new MSResponse();
MSUser user = null;
if (null == userName || null == userPwd || userName.length() <= 0 || userPwd.length() <= 0) {
MSResponseEnum responseEnum = MSResponseEnum.Login4SiginInvalidInfo;
response.setCode(responseEnum.getCode());
response.setMsg(responseEnum.getMsg());
} else {
user = MSUserUtil.createUser(userName, userPwd);
MSResponseEnum rspEnum = MSResponseEnum.SUCCESS;
response.setCode(rspEnum.getCode());
response.setMsg(rspEnum.getMsg());
}
response.setResults(user);
return response;
}
}

单元测试

在 IDEA 中新建 SpringBoot 工程后,默认就会创建一个测试目录。

test 目录下会有 SpringbootApplicationTests 类文件,其中 pom 文件中已经添加好了 spring-boot-starter-test 启动器。

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

springboot-test 包中已经包括了 junitmockito 类库,不需要我们额外再去添加这些库。

借助于 MockMvc 我们可以对接口进行简单的单元测试了。主要的测试核心代码如下:

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
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest
public class SpringbootApplicationTests {
@Autowired
private MockMvc mvc;
/* 登录的接口测试,GET 请求 */
@Test
public void signinTest() throws Exception {
//直接写接口的映射地址就可以了,不需要写host和port
String url = "/signin/name?username=itman&userpwd=123";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(url)
.accept(MediaType.APPLICATION_JSON)) //断言返回结果是json
.andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
//HTTP响应的返回码
int status = response.getStatus();
//HTTP响应的内容
String contentAsString = response.getContentAsString();
System.err.println(status);
System.err.println(contentAsString);
}
/* 注册的接口测试,POST 请求 */
@Test
public void signupTest() throws Exception {
String url = "/signup/name";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post(url)
.accept(MediaType.APPLICATION_JSON)
.param("username", "itman")
.param("userpwd", "123567"))
.andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
int status = response.getStatus();
String contentAsString = response.getContentAsString();
System.err.println(status);
System.err.println(contentAsString);
}
}

在上面编写的测试代码中,解释一下几个用到的注解和类。

1、@RunWith(SpringRunner.class)SpringRunnerSpringJUnit4ClassRunner 的简写,用于提供测试时的 Spring 应用上下文信息。

2、MockMvcMockMvc 是测试 Spring MVC 应用程序的主要入口,为我们的测试提供了一个模拟的应用上下文的环境。

3、@Autowired,可以对类成员变量、方法及构造函数进行标注,完成自动装配。不需要手动创建该对象,这个跟 Spring 的 IOC 机制有关。

代码写好之后,就可以进行单元测试了,直接在 signinTest 或者 signupTest 右键运行即可,不需要启动整个工程。如下图所示:

1568529858131

运行之后,可以在输出的控制台中看到信息:

1568529940948

前端请求

跨域和OPTIONS这对欢喜冤家减少跨域中的OPTIONS请求 这两篇文章中,已经跟大家分享过如何在前端页面中进行接口访问了,其中也重点讲解了如何在 SpringBoot 中解决跨域问题,这里不再赘述,感兴趣的朋友可以去看看这两篇文章。

文中的完整示例代码都在 Github 上面,需要的可以自行clone,感谢您的阅读。


临渊羡鱼不如按退而结网~

坚持原创技术分享!