table of Contents
User Registration
As a modern business platform, what is most important? of course the users, the majority of users support groups are the cornerstone of our sustainable development 顾客是上帝
, although in today God has not been taken seriously, especially a lot of the old platform for the user is anxious to hasten Out ... but is the foundation of all subscribers , then we start creating our God now!
## Creating a database
Part of the database, I'm not here to talk about, and we need, then you can go directly to the portal crawl script expensive-shop.sql
.
# # Generation UserMapper
Section on Reference: Portal
## write business logic
First, let's analyze To register a user, the system we all need to do what action?
- validate
- input string (we need to check-processed by two angles)
FrontEnd valid
Front-end verification is to reduce our server side pressure to do part of the check, this part of the check can intercept most of the bad request.
Backend valid
Back-end verification is to prevent some unscrupulous junior partner in order to bypass the front-end direct access to our server api error caused by data requests, or front-end program partners have a small bug ... no matter what kind of possibilities, are likely to cause serious s consequence.
email & mobile invalid
Because I did not pursue email / SMS server, so this step will pass, small partners can own research Kazakhstan.
- input string (we need to check-processed by two angles)
- control
create user
After checking through, you can create a user action.
Next, we can achieve business since the actual coding, we use the most basic layered architecture, until we have passedMybatis Generator
to generate the basic toolspojo
,mapper
for simple operation we just need to writeservice
andcontroller
layers to complete our development work.
## write user service
In mscx-shop-service
creating the com.liferunner.service.IUserService
interface contains two methods findUserByUserName
, and createUser
, as follows:
public interface IUserService {
/**
* 根据用户名查询用户是否存在
*
* @param username
* @return
*/
Users findUserByUserName(String username);
/**
* 创建用户
*
* @param userRequestDTO 用户请求dto
* @return 当前用户
*/
Users createUser(UserRequestDTO userRequestDTO) throws Exception;
}
Next, we need to implement this interface specific categories, as follows:
@Service
@Slf4j
public class UserServiceImpl implements IUserService {
private final String FACE_IMG = "https://avatars1.githubusercontent.com/u/4083152?s=88&v=4";
// 构造器注入
private final UsersMapper usersMapper;
private final Sid sid;
@Autowired
public UserServiceImpl(UsersMapper usersMapper, Sid sid) {
this.usersMapper = usersMapper;
this.sid = sid;
}
@Override
public Users findUserByUserName(String username) {
// 构建查询条件
Example example = new Example(Users.class);
val condition = example.createCriteria()
.andEqualTo("username", username);
return this.usersMapper.selectOneByExample(example);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Users createUser(UserRequestDTO userRequestDTO) throws Exception {
log.info("======begin create user : {}=======", userRequestDTO);
val user = Users.builder()
.id(sid.next()) //生成分布式id
.username(userRequestDTO.getUsername())
.password(MD5GeneratorTools.getMD5Str(userRequestDTO.getPassword()))
.birthday(DateUtils.parseDate("1970-01-01", "yyyy-MM-dd"))
.nickname(userRequestDTO.getUsername())
.face(this.FACE_IMG)
.sex(SexEnum.secret.type)
.createdTime(new Date())
.updatedTime(new Date())
.build();
this.usersMapper.insertSelective(user);
log.info("======end create user : {}=======", userRequestDTO);
return user;
}
}
There are several places it is necessary to explain:
UserServiceImpl # findUserByUserName Description
tk.mybatis.mapper.entity.Example
Constructed by the use of query parameters mybatis Example, if there is a plurality of query conditions, can beexample.createCriteria().addxxx
added one by one.
UserServiceImpl # createUser Description
@Transactional(propagation = Propagation.REQUIRED)
, Open transaction, select the transaction propagation levelREQUIRED
, represents a transaction must be present, if the caller transaction does not exist, then the method will open a new own thing, if the caller itself there is an active transaction, then this method will added into it (with the total death).org.n3r.idworker.Sid
This is an open source distributed ID generator component, portal , later given the chance, I will write a special article id generator.MD5GeneratorTools
MD5 is used for data encryption tools, you can download the source code. You can also use directjava.security.MessageDigest
direct encryption to achieve, in short, password can not be stored in plain text on the line.SexEnum
This is a type of enumeration gender representation in our encoding specifications, requirements as much as possible not to appearMagic number
, the development community is often said that the magic number (ie, 1,2,300 ...)- Here's print journal, one might ask why you did not notice like this:
private final static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
, it is because we are in the beginning, we have introducedlombok
dependence not remember the students can refer to the portal . Here dependence, it inherited a lot of logging component, we only need to use an annotationlombok.extern.slf4j.Slf4j
to open the log, uselog.info..
it. UserRequestDTO
What is a ghost? In the process of our development, is likely to be high-volume parameters need to be passed, then if we usexxx#(String aa,Integer bb,Boolean cc...)
makes us the number of very annoying, but do not look beautiful, this time we can choose to create a new object to help us transfer data, so that is ourUserRequestDTO
target, so-calledDTO
isData Transfer Object
an acronym, as the name implies, it is used to transfer data objects used.
## write user controller
Also in mscx-shop-api
, create com.liferunner.api.controller.UserController
, implement user-created.
@RestController
@RequestMapping(name = "/users")
@Slf4j
@Api(tags="用户管理")
public class UserController {
@Autowired
private IUserService userService;
@ApiOperation("校验是否重名")
@GetMapping("/validateUsername")
public JsonResponse validateUsername(@RequestParam String username) {
// 判断用户名是否非法
if (StringUtils.isBlank(username))
return JsonResponse.errorMsg("用户名不能为空!");
if (null != userService.findUserByUserName(username))
return JsonResponse.errorMsg("用户名已存在!");
// 用户名可用
return JsonResponse.ok();
}
@ApiOperation("创建用户")
@PostMapping("/create")
public JsonResponse createUser(@RequestBody UserRequestDTO userRequestDTO) {
try {
if (StringUtils.isBlank(userRequestDTO.getUsername()))
return JsonResponse.errorMsg("用户名不能为空");
if (null != this.userService.findUserByUserName(userRequestDTO.getUsername())) {
return JsonResponse.errorMsg("用户名已存在!");
}
if (StringUtils.isBlank(userRequestDTO.getPassword()) ||
StringUtils.isBlank(userRequestDTO.getConfimPassword()) ||
userRequestDTO.getPassword().length() < 8) {
return JsonResponse.errorMsg("密码为空或长度小于8位");
}
if (!userRequestDTO.getPassword().equals(userRequestDTO.getConfimPassword()))
return JsonResponse.errorMsg("两次密码不一致!");
val user = this.userService.createUser(userRequestDTO);
if (null != user)
return JsonResponse.ok(user);
} catch (Exception e) {
log.error("创建用户失败,{}", userRequestDTO);
}
return JsonResponse.errorMsg("创建用户失败");
}
}
UserController#validateUsername(username) 说明
JsonResponse
The object is returned to the client in order to facilitate a uniform format encapsulated data objects.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JsonResponse {
// 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper();
// 响应业务状态
private Integer status;
// 响应消息
private String message;
// 响应中的数据
private Object data;
public static JsonResponse build(Integer status, String msg, Object data) {
return new JsonResponse(status, msg, data);
}
public static JsonResponse ok(Object data) {
return new JsonResponse(data);
}
public static JsonResponse ok() {
return new JsonResponse(null);
}
public static JsonResponse errorMsg(String msg) {
return new JsonResponse(500, msg, null);
}
public static JsonResponse errorMap(Object data) {
return new JsonResponse(501, "error", data);
}
public static JsonResponse errorTokenMsg(String msg) {
return new JsonResponse(502, msg, null);
}
public static JsonResponse errorException(String msg) {
return new JsonResponse(555, msg, null);
}
public static JsonResponse errorUserQQ(String msg) {
return new JsonResponse(556, msg, null);
}
public JsonResponse(Object data) {
this.status = 200;
this.message = "OK";
this.data = data;
}
public Boolean isOK() {
return this.status == 200;
}
}
UserController#createUser(UserRequestDTO) 说明
- As is stated above, a variety of verification need to do first
- Success, returns
JsonResponse
- Observant students may have seen above there are a few notes
@Api(tags="用户管理")
,@ApiOperation("创建用户")
this is Swagger's comments, and we'll discuss in the next section to find out more, and how to generateoff-line docs
.
Test API
After we each modification completed, as far as possible the mvn clean install
time, because we belong to different of the project, if you do not reinstall, occasional problems may cast doubt on life.
...
[INFO] expensive-shop ..................................... SUCCESS [ 1.220 s]
[INFO] mscx-shop-common ................................... SUCCESS [ 9.440 s]
[INFO] mscx-shop-pojo ..................................... SUCCESS [ 2.020 s]
[INFO] mscx-shop-mapper ................................... SUCCESS [ 1.564 s]
[INFO] mscx-shop-service .................................. SUCCESS [ 1.366 s]
[INFO] mscx-shop-api ...................................... SUCCESS [ 4.614 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 20.739 s
[INFO] Finished at: 2019-11-06T14:53:55+08:00
[INFO] ------------------------------------------------------------------------
When you see the results of the above operation, you can start testing our application on-line friends ~
UserController#validateUsername(username) 测试
There are many ways to test the API, for example curl localhost:8080/validateUsername
, in such super popular Postman
is completely ok, I am here is before the first chapter of a plug-and everyone said Restful Toolkit(可以实现和postman一样的简单效果,同时还能帮助我们生成一部分测试信息)
, when we start the application, the following picture,
We can see that the plug-in to help us generate several test methods, such as we click validateUsername
, it will generate the current method is below contains a username
parameter GET
method demoData
is the default plug-in to our test data generated. It can be freely modified.
Click Send:
you can see the request is successful, and returns JSON data format our custom.
UserController#createUser(UserRequestDTO) 测试
Then we continue to test the user registration interface to request the following:
you can see, when we choose create
the time method, plug-in automatically help us set the request type POST
, and RequestBody
default values also helped us to create, I only modified the default username
and password
the value confimPassword
of I did not change the default value, that according to our validation logic, it should be returned return JsonResponse.errorMsg("两次密码不一致!");
to this line, click Send:
modifications confimPassword
to 12345678
, click Send:
you can see, create user success, and will return the user to create our current customers request end. So we continue to create repeated clicks, what will happen? Continue Send:
you can see, our users have also become effective verification repeat it.
Notice under section
The next section we will learn how to use Swagger API interface to automatically generate documentation to the next front-end, as well as the situation if there is no external network, or when you need a third-party platform and docking, how we generate 离线文档
to the third party.
gogogo!