[Springboot develop monomer web shop] 5. user login and Home show


User login

In the previous article we implemented user registration and authentication, then we continue to achieve its login, and after a successful login information to be displayed on the page.
Next, we write code.


Achieve service

In the com.liferunner.service.IUserServiceAdd user login interface methods:

public interface IUserService {
    ...
    /**
     * 用户登录
     * @param userRequestDTO 请求dto
     * @return 登录用户信息
     * @throws Exception
     */
    Users userLogin(UserRequestDTO userRequestDTO) throws Exception;
}

Then, in the com.liferunner.service.impl.UserServiceImplimplementation class implementation:

@Service
@Slf4j
public class UserServiceImpl implements IUserService {
    ...
    @Override
    public Users userLogin(UserRequestDTO userRequestDTO) throws Exception {
        log.info("======用户登录请求:{}", userRequestDTO);
        Example example = new Example(Users.class);
        val condition = example.createCriteria();
        condition.andEqualTo("username", userRequestDTO.getUsername());
        condition.andEqualTo("password", MD5GeneratorTools.getMD5Str(userRequestDTO.getPassword()));
        val user = this.usersMapper.selectOneByExample(example);
        log.info("======用户登录处理结果:{}", user);
        return user;
    }
}

Error Tips:
Here's a little 坑点, we must pay attention, use selectOneByExample()the query when the process the incoming parameters must be noted that tk.mybatis.mapper.entity.Exampleinstance, rather than tk.mybatis.mapper.entity.Example.Criteriaotherwise, will be reported dynamically generated SQL query error information is as follows:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'distinct' in 'class tk.mybatis.mapper.entity.Example$Criteria'
  at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92)
  at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440)
  at com.sun.proxy.$Proxy106.selectOne(Unknown Source)
  at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:159)
  at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:87)
  at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:93)
  at com.sun.proxy.$Proxy109.selectOneByExample(Unknown Source)
  at com.liferunner.service.impl.UserServiceImpl.userLogin(UserServiceImpl.java:80)
  ...

When writing new code, it is particularly vulnerable on one line written query variables, the next line directly with the open, the more people the more simple error can not start.

Realization Controller

@RestController
@RequestMapping(value = "/users")
@Slf4j
@Api(tags = "用户管理")
public class UserController {
    ...
    @ApiOperation(value = "用户登录", notes = "用户登录接口")
    @PostMapping("/login")
    public JsonResponse userLogin(@RequestBody UserRequestDTO userRequestDTO,
                                  HttpServletRequest request,
                                  HttpServletResponse response) {
        try {
            if (StringUtils.isBlank(userRequestDTO.getUsername()))
                return JsonResponse.errorMsg("用户名不能为空");
            if (StringUtils.isBlank(userRequestDTO.getPassword()) ||
                    userRequestDTO.getPassword().length() < 8) {
                return JsonResponse.errorMsg("密码为空或长度小于8位");
            }
            val user = this.userService.userLogin(userRequestDTO);
            UserResponseDTO userResponseDTO = new UserResponseDTO();
            BeanUtils.copyProperties(user, userResponseDTO);
            log.info("BeanUtils copy object {}", userResponseDTO);
            if (null != userResponseDTO) {
                // 设置前端存储的cookie信息
                CookieTools.setCookie(request, response, "user",
                        JSON.toJSONString(userResponseDTO), true);
                return JsonResponse.ok(userResponseDTO);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("用户登录失败,{},exception = {}", userRequestDTO, e.getMessage());
        }
        return JsonResponse.errorMsg("用户登录失败");
    }
}

In the above code, the basic calibration problem will not go into, we focus on a few new features information:

  • com.liferunner.dto.UserResponseDTOWe will need to show it to the front of the data package for a new return object, we query from the database of Userspojo contains all the user data, such as where password, mobileand so some users private data is not supposed to show it to the front, even to show that also need to go through desensitization, and encryption. Thus, common practice is to package a new object is returned, which needs to contain only the front end of the data field needs it.
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "用户信息返回DTO", description = "用户登录成功后需要的返回对象")
public class UserResponseDTO {
    /**
     * 主键id
     */
    private String id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 昵称 昵称
     */
    private String nickname;

    /**
     * 头像
     */
    private String face;

    /**
     * 性别  1:男  0:女  2:保密
     */
    private Integer sex;
}

Here suggest that you use Ctrl+Cour com.liferunner.pojo.Usersobject, and then delete the fields we do not need it, why do 建议it, it is because a good do.

  • org.springframework.beans.BeanUtils.copyProperties(user, userResponseDTO);
    As you can see, here is the direct use of Spring BeanUtilsthe value of the copy tool classes, it reduces us to loop through each field one by one to the assignment (SetValue)of work. (Also a lazy little trick Oh, this is not right -)

  • CookieTools.setCookie();
    We have mentioned before, under normal circumstances, after the user logs on us, data will be stored in the local browser Cookie, such as my login baidu.com:
    baidu
    At this point, the mouse in the picture on the left side of the Cookies => www.baidu.comright clear, then refresh our current interface again, the effect as follows:
    clear cookies
    we can see from the login state has become the exit status, and Cookiesthe content is also a lot less, which shows that Baidu is to our users after login information encrypted and stored in a browser cookie.
    We can see Jingdong, Taobao, etc., is also based on achieved in this way, at the beginning of the opening once said, our system is based on the demo production to achieve, then we do with mainstream implementation. Of course, some students will say, that we should pass data to the front end, so that the front end to achieve! ! ! Of course, you're right, but we have one implementation, for us personally should not hurt, right?
    Here you need a utility class, we can at github portal to download code. Directory com.liferunner.utils.CookieTools.

  • com.alibaba.fastjson.JSON.toJSONString(userResponseDTO)
    Because we want the return of an object, but cookiewe need to put that Stringhere we introduced alibaba's JSON tool, mscx-shop-common/pom.xmladding it depends on:

        <dependencies>
          <dependency>
              <groupId>com.alibaba</groupId>
              <artifactId>fastjson</artifactId>
              <version>1.2.56</version>
          </dependency>
      </dependencies>

The user logs out

After the end user, we need to be user logs out from the system, because our users login information will be stored in a browser cookie, so we need to delete the associated user cache based on user logout operation:

    @ApiOperation(value = "用户登出",notes = "用户登出",httpMethod = "POST")
    @PostMapping("/logout")
    public JsonResponse userLogout(@RequestParam String uid,
        HttpServletRequest request,HttpServletResponse response){
        // clear front's user cookies
        CookieTools.deleteCookie(request,response,"user");
        // return operational result
        return JsonResponse.ok();
    }

Development and debugging small welfare

java log tracking

General electric business scenarios, the response time of the request has an extremely stringent requirements, such as when you buy a commodity at a site, if every click of a button should wait, or the system Caton feel it, you will not hesitate to select the upper right corner 小红叉, get rid of it. Therefore, in the development of our system, often we need to monitor the response time of our request, even to test stress tests. But let us do every method to achieve such a request is clearly unreasonable and even that is to allow developers uncomfortable, so we have to achieve a common practice, and that is through AOP, aspect-oriented to achieve. Section on basic use, we can refer to the AOP Portal , Next, we start coding.
According to springbootrealize the function Trilogy:
SETP 1. Add dependent

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

step 2. startup configuration (not just ignore this step)
SETP 3. annotated
in our mscx-shop-apiproject, create a com.liferunner.api.aspectpackage, and then create the com.liferunner.api.aspect.CommonLogAspectfollowing code:

package com.liferunner.api.aspect;

import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * CommonLogAspect for : AOP切面实现日志确认
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang | 若初</a>
 * @since 2019/11/11
 */
@Component
@Aspect
@Slf4j
public class CommonLogAspect {

    @Around("execution(* com.liferunner.api.controller..*.*(..))")
    public void recordLogTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("----------- {}.{} process log time started.---------------",
                proceedingJoinPoint.getTarget().getClass(),
                proceedingJoinPoint.getSignature().getName());

        val startTime = System.currentTimeMillis();
        proceedingJoinPoint.proceed();
        val afterTime = System.currentTimeMillis();
        if (afterTime - startTime > 1000) {
            log.warn("cost : {}", afterTime - startTime);
        } else {
            log.info("cost : {}", afterTime - startTime);
        }

        log.info("----------- {}.{} process log time ended.---------------",
                proceedingJoinPoint.getSourceLocation().getClass(),
                proceedingJoinPoint.getSignature().getName());
    }
}
  • The first line of the log on our behalf which method you want to monitor what kind of
  • proceedingJoinPoint.proceed();Representation execution
  • When the request is checked 1000ms, we use log.warn(...)a log warning

step 4. The demo

  • Users consuming queries
    get
  • Registered users consuming
    insert

From the chart, we can clearly see that every time we request time-consuming, and then it can be targeted to optimize every method! ! !

sql log tracking

In the process of our development, often run against the database of the CRUDoperation, however, because we used mybatisto dynamically generate a simple SQL query, rather than manually writing, such as we are in UserServiceImpl.javathe user's query and implement user registration code the tk.mybatis.mapper.entity.Examplewellthis.usersMapper.insertSelective(user);


    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;
    }

Once having problems, we often do not know in the end is where the error occurred, this time we are SQLthere a problem we do not know, so let's configure a way for us to small implementations of SQL:

1. Set logging configuration (FIG.)
log4j.properties
2. Modification mybatis configuration ( log-impl: org.apache.ibatis.logging.stdout.StdOutImpl)
mybatis
3. SELECTThe demo
result
4. INSERTdemonstration effect
INSERT
from the console can be seen in FIG JDBC operation twice, the first time is in fact our username check. The second INSERTis the real insert.

By demonstrating the above results, we can think of, this log needle solve problems in our daily development is very necessary. But we must remember that, at the time of production, the log must be closed, otherwise after a large amount of data once, the performance of the system will cause serious injury! ! !

Source download

Github Portal
Gitee Portal

Notice under section


The next section we will continue to develop a core part of our electricity supplier - Product and display ads, to use in the course of any development component, I will be a special presentation by one of the brothers late panic!

gogogo!

Guess you like

Origin www.cnblogs.com/zhangpan1244/p/11839530.html