Catalog
- User registration
As a modern e-commerce platform, what is the most important? of course is the user, the majority of user groups are the cornerstone to support our sustainable development, and the customer is God. Although God has not been paid attention to nowadays, especially many platforms hate to rush Out for old users... But user volume is the basis of everything, so let's start to create our God!
##Create database
I won't talk about the part of database here. You can go directly if you need Portal Grab the script expensive-shop.sql
##Generate UserMapper
Refer to the previous section: Portal
##Write business logic
First of all, let's analyze what we need to do to register a user?
- validate
- Input string (we need to check the input through two angles)
-
FrontEnd valid
Front end verification is a part of verification to reduce the pressure on our server. This part of verification can intercept most error requests.
-
Backend valid
Back end verification is to prevent some illegal small partners from bypassing the front end to directly access our api, causing data request server errors, or bug s in front-end small partner programs... No matter which possibility, there may be serious consequences.
-
-
email & mobile invalid
Because I didn't pursue email / SMS sending server, so this step is pass, and my friends can study it on their own.
- Input string (we need to check the input through two angles)
- control
-
create user
After the verification is passed, you can create a user.
Next, we can actually code and implement the business. We use the most basic layered architecture. Before that, we have generated the basic POJO and mapper through the Mybatis Generator tool. For simple operations, we only need to write the service and controller layers to complete our development work.
-
##Write user service
Create the com.liferunner.service.IUserService interface in mscx shop service, including two methods findUserByUserName and createUser, as follows:
public interface IUserService { /** * Query whether the user exists according to the user name * * @param username * @return */ Users findUserByUserName(String username); /** * Create user * * @param userRequestDTO User requests dto * @return Current user */ Users createUser(UserRequestDTO userRequestDTO) throws Exception; }
Next, we need to specifically implement this interface class, as follows:
@Service @Slf4j public class UserServiceImpl implements IUserService { private final String FACE_IMG = "https://avatars1.githubusercontent.com/u/4083152?s=88&v=4"; // Constructor Injection 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) { // Build query criteria 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()) //Generate distributed 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; } }
Here are a few places to explain:
Userserviceimpl? Finduserbyusername description
- tk.mybatis.mapper.entity.Example use Example to build query parameters of mybatis. If there are multiple query conditions, you can add them one by one through Example. Createterritory(). Addxxx.
Userserviceimpl? CREATEUSER description
- @Transactional(propagation = Propagation.REQUIRED). When transaction propagation level is selected as REQUIRED, it means that there must be a transaction. If the caller does not have a transaction, this method will start a new thing by itself. If the caller itself exists in an active transaction, this method will join it (live and die together).
- org.n3r.idworker.Sid, an open source distributed ID generator component, Portal Later, if you have the opportunity, you will write an id generator article.
- MD5 generator tools is a tool class for MD5 encryption of data. You can download it in the source code. You can also use java.security.MessageDigest to directly encrypt. In short, passwords cannot be stored in plaintext.
- SexEnum is an enumeration of gender types. In our coding specification, we try to avoid the occurrence of Magic number, which is often called Magic number by the development community (i.e. 1,2300...)
- In the log printing here, someone may ask why you didn't declare something similar: private final static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); this is because we introduced lombok dependency at the beginning. For those who don't remember, please refer to Portal . In this dependency, it inherits many log components. We only need to use a single annotation, lombok.extern.slf4j.Slf4j, to open the log. Use log.info.
- What the hell is UserRequestDTO? In the process of our development, there may be a large number of parameters that need to be passed. If we use XXX (string AA, integer BB, Boolean CC...), we will be annoyed and look ugly. At this time, we can choose to create a new object to help us pass data, which is our UserRequestDTO object. The so-called DTO is data tr The acronym of answer object, as the name implies, is used to transfer data objects.
##Write user controller
Also in mscx shop API, create com.liferunner.api.controller.UserController to realize user creation.
@RestController @RequestMapping(name = "/users") @Slf4j @Api(tags="user management") public class UserController { @Autowired private IUserService userService; @ApiOperation("Verify duplicate name") @GetMapping("/validateUsername") public JsonResponse validateUsername(@RequestParam String username) { // Judge whether the user name is illegal if (StringUtils.isBlank(username)) return JsonResponse.errorMsg("User name cannot be empty!"); if (null != userService.findUserByUserName(username)) return JsonResponse.errorMsg("User name already exists!"); // User name available return JsonResponse.ok(); } @ApiOperation("Create user") @PostMapping("/create") public JsonResponse createUser(@RequestBody UserRequestDTO userRequestDTO) { try { if (StringUtils.isBlank(userRequestDTO.getUsername())) return JsonResponse.errorMsg("User name cannot be empty"); if (null != this.userService.findUserByUserName(userRequestDTO.getUsername())) { return JsonResponse.errorMsg("User name already exists!"); } if (StringUtils.isBlank(userRequestDTO.getPassword()) || StringUtils.isBlank(userRequestDTO.getConfimPassword()) || userRequestDTO.getPassword().length() < 8) { return JsonResponse.errorMsg("Password is empty or less than 8 bits in length"); } if (!userRequestDTO.getPassword().equals(userRequestDTO.getConfimPassword())) return JsonResponse.errorMsg("The two passwords are inconsistent!"); val user = this.userService.createUser(userRequestDTO); if (null != user) return JsonResponse.ok(user); } catch (Exception e) { log.error("Failed to create user,{}", userRequestDTO); } return JsonResponse.errorMsg("Failed to create user"); } }
Usercontroller ා validateusername (username) description
- The JsonResponse object is a data object encapsulated for convenient return to the client in a unified format.
@Data @NoArgsConstructor @AllArgsConstructor public class JsonResponse { // Defining jackson objects private static final ObjectMapper MAPPER = new ObjectMapper(); // Respond to business status private Integer status; // Response message private String message; // Data in response 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) description
- As mentioned above, various verifications need to be done first
- JsonResponse if successful
- Careful students may have seen several annotations @ Api(tags = "user management"), @ ApiOperation("create user"). This is Swagger's annotation. We will discuss in detail in the next section and how to generate off-line docs.
Test API
After each modification, we try to install MVN clean once as much as possible, because we belong to different project s. If we don't reinstall it once, the problems we encounter occasionally will make people doubt 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 above results, you can start our application and test it
Usercontroller ා validateusername (username) test
There are many ways to test the API, such as curl localhost:8080/validateUsername. For example, it's ok to use the super popular postman. I'm using the restful Toolkit (which can achieve the same simple effect as postman and help us generate some test information) as mentioned in the first article. When we start the application, The effect is as follows:,
We can see that the plug-in helps us generate several test methods. For example, if we click validateUsername, the current method is a GET method containing the username parameter. demoData is the test data generated by the plug-in by default. It can be modified at will.
Click Send:
You can see that the request is successful, and the JSON format data we customized is returned.
Usercontroller? CREATEUSER (userrequestdto) test
Then we continue to test the user registration interface, and the request is as follows:
As you can see, when we select the create method, the plug-in automatically sets the request type to POST for us, and the default value of RequestBody also helps us generate. I only modified the default username and password values, but I didn't change the default value of confimPassword. According to our verification logic, it should return JsonResponse.errorMsg("the two passwords are different To! "); in this line, click Send:
Modify the confimPassword to 12345678, and click Send:
As you can see, the user was created successfully and the currently created user was returned to our request client. So what happens if we continue to click and create again and again? Continue Send:
As you can see, our authentication repeat users have also taken effect.
Notice of next quarter
In the next section, we will learn how to use Swagger to automatically generate API interface documents to the front-end, and how to generate offline documents to the third-party if there is no external network, or if we need to interface with a third-party platform.
gogogo!