5. 사용자 로그인 및 홈 쇼 [Springboot 단량체 웹 상점을 개발]


사용자 로그인

우리는 사용자 등록 및 인증을 구현 이전 기사에서, 우리는 로그인을 달성하기 위해 계속 성공적인 로그인 정보 후 페이지에 표시 할 수 있습니다.
다음으로, 우리는 코드를 작성합니다.


서비스를 달성

에서 com.liferunner.service.IUserService추가 사용자 로그인 인터페이스 방법 :

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

그런 다음에 com.liferunner.service.impl.UserServiceImpl구현 클래스의 구현 :

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

오류 팁 :
여기에 조금의 坑点, 우리가 사용하는, 관심을 지불해야 selectOneByExample()프로세스가 입력 매개 변수를 주목해야하는 경우 쿼리를 tk.mybatis.mapper.entity.Example인스턴스보다는 tk.mybatis.mapper.entity.Example.Criteria같은 다음, 그렇지 않으면보고됩니다 동적으로 생성 된 SQL 쿼리 오류 정보는 다음과 같습니다

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)
  ...

새로운 코드를 작성하면, 한 줄 작성 쿼리 변수에 특히 취약, 직접 오픈과 다음 줄은 더 많은 사람들이 더 간단한 오류를 시작할 수 없습니다.

실현 컨트롤러

@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("用户登录失败");
    }
}

위의 코드에서 다루지 않는 기본 보정 문제, 우리는 몇 가지 새로운 기능 정보에 초점 :

  • com.liferunner.dto.UserResponseDTO우리는 새로운 수익 객체의 데이터 패키지의 전면에 표시해야합니다, 우리의 데이터베이스에서 쿼리 UsersPOJO 등 모든 사용자 데이터를 포함 password, mobile일부 사용자 있도록 개인 데이터도 전면에게 보여 안됩니다 쇼에 있음을 또한 탈감작 및 암호화를 통해 이동해야합니다. 따라서, 일반적인 관행은 새로운 객체가 데이터 필드의 프론트 엔드를 필요로를 포함 할 필요가있는, 반환되는 패키지입니다.
@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;
}

여기에 사용하는 것이 좋습니다 Ctrl+C우리의 com.liferunner.pojo.Users목적을 다음 할 우리가 왜 필요하지 않은 분야, 삭제 建议잘 할 때문입니다, 그것을.

  • org.springframework.beans.BeanUtils.copyProperties(user, userResponseDTO);
    당신이 볼 수 있듯이, 여기의 직접 사용하는 것입니다 Spring BeanUtils복사 도구 클래스의 값이,이 과제에 하나씩 각 필드 하나를 통해 루프 우리를 줄여 (SetValue)작업. (또한 게으른 약간의 트릭 오, 이건 옳지 않아 -)

  • CookieTools.setCookie();
    우리의 사용자 로그 데이터가 로컬 브라우저에 저장됩니다 후 우리는 정상적인 상황에서, 이전에 언급 한 Cookie같은 내 로그인으로, baidu.com:
    바이두
    이 시점에서, 왼쪽의 그림에서 마우스 Cookies => www.baidu.com오른쪽 clear, 다음, 다시 효과를 현재의 인터페이스를 새로 고침 다음과 같이
    쿠키 삭제
    로그인 상태가 종료 상태가되었다에서 우리가 볼 수 있으며, Cookies내용은 로그인 정보는 암호화되어 브라우저의 쿠키에 저장 한 후 바이두는 우리의 사용자라고하는 쇼도 훨씬 덜합니다.
    우리는 등 Jingdong, Taobao의를 볼 수 있습니다, 또한 말했다 일단 개방의 시작 부분에 이러한 방법으로 달성을 기반으로, 우리의 시스템을 달성하기 위해 데모 생산을 기반으로, 우리는 주류 구현으로한다. 물론, 일부 학생들은 우리가 프론트 엔드 달성 것을, 프론트 엔드에 데이터를 전달해야한다고 말할 것이다! ! ! 물론, 당신 말이 맞아,하지만 우리는 하나의 구현을 가지고, 우리가 개인적으로 상처를 안 들어 맞죠?
    다음은 유틸리티 클래스가 필요, 우리의 수 GitHub의 포털 다운로드 코드. 디렉토리 com.liferunner.utils.CookieTools.

  • com.alibaba.fastjson.JSON.toJSONString(userResponseDTO)
    우리가 객체의 반환을 원하지만, 때문에 cookie우리는 그 둘 필요 String, 우리는 알리바바의 JSON 도구를 도입 여기에 mscx-shop-common/pom.xml추가가에 따라 달라집니다

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

사용자가 로그 아웃

우리의 사용자 로그인 정보가 브라우저 쿠키에 저장되기 때문에 우리는 사용자 로그 아웃 작업에 따라 관련 사용자 캐시를 삭제해야하므로 최종 사용자 후, 우리는, 사용자가 시스템에서 로그 아웃 할 필요가 :

    @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();
    }

개발 및 작은 복지 디버깅

자바 로그 추적

일반 전기 비즈니스 시나리오는 요청의 응답 시간은 버튼을 클릭 할 때마다 기다려야 경우, 사이트에서 상품을 구입하거나 시스템이 그것을 느낄 Caton 때와 매우 엄격한 요구 사항을 가지고, 당신은 주저하지 않을 것이다 오른쪽 상단을 선택 小红叉, 그것을 제거. 따라서, 우리의 시스템의 개발에, 종종 우리는 심지어 시험 스트레스 테스트에, 우리의 요청의 응답 시간을 모니터링 할 필요가있다. 그러나 우리는 모든 방법은 이러한 요청은 우리가 일반적인 관행을 달성해야하므로, 개발자가 불편 수 있도록하는 것입니다 심지어 명확하게 불합리하고 달성 할 수 있도록, 그것은 통해 AOPaspect 지향 달성하기 위해. 기본 사용에 대한 부분은, 우리가 참조 할 수 AOP 포털 다음, 우리는 코딩을 시작.
에 따르면 springboot기능 부작을 실현 :
SETP 1. 따라 추가

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

2. 시작 구성 (다만이 단계를 무시하지) 단계
주석 SETP 3.
우리의 mscx-shop-api프로젝트를 만들 com.liferunner.api.aspect패키지를 한 후 생성 com.liferunner.api.aspect.CommonLogAspect다음 코드를 :

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());
    }
}
  • 당신은 어떤 종류의를 모니터링 할 방법 우리를 대신하여 로그의 첫 번째 행
  • proceedingJoinPoint.proceed();표현의 실행
  • 요청이 1000MS를 선택하면, 우리가 사용하는 log.warn(...)로그 경고

4 단계 데모

  • 쿼리를 소비하는 사용자
    가져 오기
  • 소모 등록 된 사용자
    끼워 넣다

차트에서, 우리는 분명히 우리가 시간이 많이 소요 요청하고이 모든 방법을 최적화하기 위해 목표로 할 수있는 모든 시간을 볼 수 있습니다! ! !

SQL 로그 추적

우리의 개발 과정에서 종종의 데이터베이스에 대해 실행 CRUD우리가 사용했기 때문에, 그러나, 동작을 mybatis동적으로 간단한의 SQL 쿼리를 생성하는 대신 수동으로 우리가있는 등, 작성하는 UserServiceImpl.java사용자의 쿼리 및 사용자 등록 코드를 구현 tk.mybatis.mapper.entity.Examplethis.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;
    }

문제가되면, 우리는 종종, 오류가 발생한 곳이다 결국 우리가이 시간을 모르는 SQL우리가 모르는 문제가, 그래서 우리를 위해 방법을 구성있을 수 있습니다 SQL의 작은 구현에 :

1. 설정 로깅 구성 (도입니다.)
log4j.properties
2. 변형 예는 구성 (MyBatis로 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl)
MyBatis로
3. SELECT데모
결과
INSERT데몬스트레이션 효과
끼워 넣다
콘솔에서 두번도 JDBC 동작에서 볼 수는 최초로 실제로 우리 자명 확인. 두 번째는 INSERT실제 삽입합니다.

위의 결과를 보여줌으로써, 우리는이 로그 바늘이 우리의 일상 개발 문제를 해결, 생각할 수있는 것은 매우 필요하다. 그러나 우리가 기억해야하며, 생산시, 로그 그렇지 않으면 한 번에 많은 양의 데이터 후, 시스템의 성능이 심각한 부상을 초래할 것이다 닫아야합니다! ! !

소스 다운로드

Github에서 포털
Gitee 포털

섹션 공지 사항


다음 섹션은 우리가 전력 공급의 핵심 부분을 개발하는 것입니다 - 제품 광고와 디스플레이 광고를, 모든 개발 구성 요소의 과정에서 사용하기에, 나는 늦게 당황 형제 중 하나에 의해 특별 발표 될 것입니다!

gogogo!

추천

출처www.cnblogs.com/zhangpan1244/p/11839530.html