[springboot development monomer web shop] 3. User registration implementation

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.

  • 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!

Tags: Java Database Mybatis Lombok SQL

Posted on Wed, 06 Nov 2019 19:49:19 -0500 by srfdriver22