SpringBoot写一个登陆注册功能,和期间走的坑

文章目录

  • 前言
  • 1. 首先介绍项目的相关技术和工具:
  • 2. 首先创建项目
  • 3. 项目的结构
    • 3.1实体类:
    • 3.2 Mapper.xml
    • 3.3 mapper.inteface
    • 3.4 Service
    • 3.5 Controller
    • 3.6 html页面
    • 3.7 yml文件配置
    • 3.8 POM文件依赖
  • 4. 踩坑秘籍
    • 4.1 xml文件返回结果是list的size为1,但是结果为null
    • 4.2 Controller返回到html
    • 4.3 关于静态资源的配置
    • 4.4 Swagger 配置
    • 4.5 mapstruct的配置和使用
  • 代码下载地址

前言

   最近在做一个关于SpringBoot的项目,首先从最简单的注册登陆开始,从前端到后端。

1. 首先介绍项目的相关技术和工具:

开发工具使用IDEA,技术使用SpringBoot2.1.3+Mybatis+Jpa+mysql,项目中主要使用Mybatis,jpa只做了demo,实体转换使用的是mapstruct,集成了swagger文档配置,redis缓存demo。

2. 首先创建项目

两种方式:1、直接在IDEA中file–>new–>project,选择spring Initalizr创建一个springBoot项目。
SpringBoot写一个登陆注册功能,和期间走的坑_第1张图片
2、或者直接在spring的官网创建一个springboot项目springBoot官网创建项目

3. 项目的结构

首先项目的结构和普通的spring项目是一样的,采用controller、service、dao三层
SpringBoot写一个登陆注册功能,和期间走的坑_第2张图片
接下来项目采用逆向介绍:
实体—>Mapper.xml—>Mapper.inteface–>service–>controller—>html
项目中的一些实体和mybatis的代码,采用mybatis generator逆向生成。
如果逆向生成不太懂,请自行百度了解或点击Mybatis-Generator之最完美配置详解

3.1实体类:

@Table(name = "user_info")
@Entity
public class UserInfo extends BaseEntity{

    @Id
    @Column(name = "USER_ID")
    private Long userId;

    @Column(name = "USER_NICK_NAME")
    private String userNickName;

    @Column(name = "USER_SUR_NAME")
    private String userSurName;

    @Column(name = "USER_NAME")
    private String userName;

    @Column(name = "USER_DESC")
    private String userDesc;

    @Column(name = "USER_SEX")
    private Boolean userSex;

    @Column(name = "USER_PHONE")
    private String userPhone;

    @Column(name = "USER_EMAIL")
    private String userEmail;

    @Column(name = "USER_HOME")
    private String userHome;

    @Column(name = "USER_BIRTHDAY")
    private Date userBirthday;

    @Column(name = "USER_REGISTER_DATE")
    private Date userRegisterDate;

    @Column(name = "USER_LEVEL")
    private Long userLevel;

    @Column(name = "PASS_WORD")
    private String passWord;

    @Column(name = "LOGIN_NUM")
    private Long loginNum;
    GetSet方法省略

由于项目中集成了Jpa所以实体类上有表和列的注解。

3.2 Mapper.xml




  
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  
  
    USER_ID, USER_NICK_NAME, USER_SUR_NAME, USER_NAME, USER_DESC, USER_SEX, USER_PHONE, 
    USER_EMAIL, USER_HOME, USER_BIRTHDAY, USER_REGISTER_DATE, CREATE_DATE, UPDATE_DATE, 
    STATUS_CD, STATUS_DATE, REMARK, USER_LEVEL, PASS_WORD, LOGIN_NUM
  
  
  
    delete from user_info
    where USER_ID = #{userId,jdbcType=BIGINT}
  
  
    insert into user_info (USER_ID, USER_NICK_NAME, USER_SUR_NAME, 
      USER_NAME, USER_DESC, USER_SEX, 
      USER_PHONE, USER_EMAIL, USER_HOME, 
      USER_BIRTHDAY, USER_REGISTER_DATE, CREATE_DATE, 
      UPDATE_DATE, STATUS_CD, STATUS_DATE, 
      REMARK, USER_LEVEL, PASS_WORD, 
      LOGIN_NUM)
    values (#{userId,jdbcType=BIGINT}, #{userNickName,jdbcType=VARCHAR}, #{userSurName,jdbcType=VARCHAR}, 
      #{userName,jdbcType=VARCHAR}, #{userDesc,jdbcType=VARCHAR}, #{userSex,jdbcType=BIT}, 
      #{userPhone,jdbcType=VARCHAR}, #{userEmail,jdbcType=VARCHAR}, #{userHome,jdbcType=VARCHAR}, 
      #{userBirthday,jdbcType=TIMESTAMP}, #{userRegisterDate,jdbcType=TIMESTAMP}, #{createDate,jdbcType=TIMESTAMP}, 
      #{updateDate,jdbcType=TIMESTAMP}, #{statusCd,jdbcType=DECIMAL}, #{statusDate,jdbcType=TIMESTAMP}, 
      #{remark,jdbcType=VARCHAR}, #{userLevel,jdbcType=BIGINT}, #{passWord,jdbcType=VARCHAR}, 
      #{loginNum,jdbcType=BIGINT})
  
  
    insert into user_info
    
      
        USER_ID,
      
      
        USER_NICK_NAME,
      
      
        USER_SUR_NAME,
      
      
        USER_NAME,
      
      
        USER_DESC,
      
      
        USER_SEX,
      
      
        USER_PHONE,
      
      
        USER_EMAIL,
      
      
        USER_HOME,
      
      
        USER_BIRTHDAY,
      
      
        USER_REGISTER_DATE,
      
      
        CREATE_DATE,
      
      
        UPDATE_DATE,
      
      
        STATUS_CD,
      
      
        STATUS_DATE,
      
      
        REMARK,
      
      
        USER_LEVEL,
      
      
        PASS_WORD,
      
      
        LOGIN_NUM,
      
    
    
      
        #{userId,jdbcType=BIGINT},
      
      
        #{userNickName,jdbcType=VARCHAR},
      
      
        #{userSurName,jdbcType=VARCHAR},
      
      
        #{userName,jdbcType=VARCHAR},
      
      
        #{userDesc,jdbcType=VARCHAR},
      
      
        #{userSex,jdbcType=BIT},
      
      
        #{userPhone,jdbcType=VARCHAR},
      
      
        #{userEmail,jdbcType=VARCHAR},
      
      
        #{userHome,jdbcType=VARCHAR},
      
      
        #{userBirthday,jdbcType=TIMESTAMP},
      
      
        #{userRegisterDate,jdbcType=TIMESTAMP},
      
      
        #{createDate,jdbcType=TIMESTAMP},
      
      
        #{updateDate,jdbcType=TIMESTAMP},
      
      
        #{statusCd,jdbcType=DECIMAL},
      
      
        #{statusDate,jdbcType=TIMESTAMP},
      
      
        #{remark,jdbcType=VARCHAR},
      
      
        #{userLevel,jdbcType=BIGINT},
      
      
        #{passWord,jdbcType=VARCHAR},
      
      
        #{loginNum,jdbcType=BIGINT},
      
    
  
  
    update user_info
    
      
        USER_NICK_NAME = #{userNickName,jdbcType=VARCHAR},
      
      
        USER_SUR_NAME = #{userSurName,jdbcType=VARCHAR},
      
      
        USER_NAME = #{userName,jdbcType=VARCHAR},
      
      
        USER_DESC = #{userDesc,jdbcType=VARCHAR},
      
      
        USER_SEX = #{userSex,jdbcType=BIT},
      
      
        USER_PHONE = #{userPhone,jdbcType=VARCHAR},
      
      
        USER_EMAIL = #{userEmail,jdbcType=VARCHAR},
      
      
        USER_HOME = #{userHome,jdbcType=VARCHAR},
      
      
        USER_BIRTHDAY = #{userBirthday,jdbcType=TIMESTAMP},
      
      
        USER_REGISTER_DATE = #{userRegisterDate,jdbcType=TIMESTAMP},
      
      
        CREATE_DATE = #{createDate,jdbcType=TIMESTAMP},
      
      
        UPDATE_DATE = #{updateDate,jdbcType=TIMESTAMP},
      
      
        STATUS_CD = #{statusCd,jdbcType=DECIMAL},
      
      
        STATUS_DATE = #{statusDate,jdbcType=TIMESTAMP},
      
      
        REMARK = #{remark,jdbcType=VARCHAR},
      
      
        USER_LEVEL = #{userLevel,jdbcType=BIGINT},
      
      
        PASS_WORD = #{passWord,jdbcType=VARCHAR},
      
      
        LOGIN_NUM = #{loginNum,jdbcType=BIGINT},
      
    
    where USER_ID = #{userId,jdbcType=BIGINT}
  
  
    update user_info
    set USER_NICK_NAME = #{userNickName,jdbcType=VARCHAR},
      USER_SUR_NAME = #{userSurName,jdbcType=VARCHAR},
      USER_NAME = #{userName,jdbcType=VARCHAR},
      USER_DESC = #{userDesc,jdbcType=VARCHAR},
      USER_SEX = #{userSex,jdbcType=BIT},
      USER_PHONE = #{userPhone,jdbcType=VARCHAR},
      USER_EMAIL = #{userEmail,jdbcType=VARCHAR},
      USER_HOME = #{userHome,jdbcType=VARCHAR},
      USER_BIRTHDAY = #{userBirthday,jdbcType=TIMESTAMP},
      USER_REGISTER_DATE = #{userRegisterDate,jdbcType=TIMESTAMP},
      CREATE_DATE = #{createDate,jdbcType=TIMESTAMP},
      UPDATE_DATE = #{updateDate,jdbcType=TIMESTAMP},
      STATUS_CD = #{statusCd,jdbcType=DECIMAL},
      STATUS_DATE = #{statusDate,jdbcType=TIMESTAMP},
      REMARK = #{remark,jdbcType=VARCHAR},
      USER_LEVEL = #{userLevel,jdbcType=BIGINT},
      PASS_WORD = #{passWord,jdbcType=VARCHAR},
      LOGIN_NUM = #{loginNum,jdbcType=BIGINT}
    where USER_ID = #{userId,jdbcType=BIGINT}
  
  

关于这个xml多说一句,在代码运行期间遇到的坑:如果数据库表字段和实体的类型匹配不到,在结果返回的时候使用resultType是不能将结果正常的返回出来的,我遇到的情况是查询出数据条数为1,结果的list的size的确是1,但是里面却是null,这个就是因为字段类型不匹配,导致的数据没有被填充到指定的实体中,这个时候应该使用resultMap对表字段和实体字段进行指定。这样就能正常的返回数据了。

3.3 mapper.inteface

@Mapper
public interface UserInfoMapper{
    int deleteByPrimaryKey(Long userId);

    int insert(UserInfo record);

    int insertSelective(UserInfo record);

    UserInfo selectByPrimaryKey(Long userId);

    int updateByPrimaryKeySelective(UserInfo record);

    int updateByPrimaryKey(UserInfo record);

    List findByExample(UserInfo userInfo);
}

这里说一句注意点,这个接口是用来和xml文件进行交互的,xml文件你可以理解为是当前接口的实现类。注意点1:当前接口需要加注解@Mapper,将当前类交由spring管理。
注意点2:如果接口中的方法参数是多个(>1)的时候需要对参数加@Param进行名称的指定,这里使用注解指定的名称就是在xml中取值使用的名称而不是参数的名称,eg:String find(@Param(“aa”) int bb),如果想在xml中取到参数bb对应的值,那么就应该获取名称为aa的变量,${aa}或者#{aa}。如果方法的参数是一个或者没有,那么@Param注解可加可不加。

3.4 Service

项目中采用接口+实现类的形式:
实现类ServiceImpl:

@Service("userServiceImpl")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    public UserInfo findByName(String name) {
        return userDao.findByUserNickName(name);
    }

    @Override
    public List findAll() {
        return userDao.findAll();
    }

    @Override
    public UserInfo findOne(Long id) {
        return userDao.findById(id).isPresent()?userDao.findById(id).get():new UserInfo();
    }

    @Override
    public UserInfo save(UserInfo UserInfo) {
        return userDao.save(UserInfo);
    }

    @Override
    public UserInfo saveAndUpdate(UserInfo UserInfo) {
        return userDao.saveAndFlush(UserInfo);
    }

    @Override
    public void deleteUser(long id) {
        userDao.deleteById(id);
    }

    @Override
    public UserInfo findById(long id){
        return userInfoMapper.selectByPrimaryKey(id);
    }

    @Override
    public int insert(UserInfo userInfo) {

        //用户注册的时候只有用户名和密码,所以为用户设置必填的一些字段,
        //主键
        userInfo.setUserId(KeyUtils.UUID());
        Date nowDate = new Date();
        //注册时间、创建时间
        userInfo.setUserRegisterDate(nowDate);
        userInfo.setCreateDate(nowDate);
        //剩余登陆次数,默认5次
        userInfo.setLoginNum(L_FIVE);
        //性别,若没有则设置为true,true表示男,数据库对应的是1
        if(StringUtils.isEmpty(userInfo.getUserSex())){
            userInfo.setUserSex(true);
        }
        //用户姓氏取用户名的第一个字符
        userInfo.setUserSurName(userInfo.getUserNickName().substring(I_ZERO, I_ONE));
        userInfo.setUserName(userInfo.getUserNickName().substring(I_ONE));

        //用户状态默认有效
        userInfo.setStatusCd(StatusCdEnum.ACTIVE_ENUM.getCode());
        //用户等级
        userInfo.setUserLevel(L_ONE);
        //用户密码默认采用MD5进行加密
        userInfo.setPassWord(EncryptUtil.getInstance().MD5(userInfo.getPassWord()));

        return userInfoMapper.insert(userInfo);
    }

    @Override
    @Transactional
    public UserEnum login(UserInfo userInfo) {
        String userNickName = userInfo.getUserNickName();
        String passWord = userInfo.getPassWord();
        //用户名或密码为空,直接返回
        if(StringUtils.isEmpty(userNickName) || StringUtils.isEmpty(passWord)){
            return LOGIN_USER_PWD_NULL;
        }

        //登陆的步骤:
        //1、首先根据用户名查询数据库有效的数据且次数大于0的是否存在,若用户名不存在则直接返回,若用户名存在则继续下面的操作
        UserInfo ui = new UserInfo();
        ui.setStatusCd(StatusCdEnum.ACTIVE_ENUM.getCode());
        ui.setLoginNum(L_ZERO);
        ui.setUserNickName(userNickName);
        List userInfos = userInfoMapper.findByExample(ui);
        if(CollectionUtils.isEmpty(userInfos)){
            return LOGIN_USER_NULL;
        }
        //2、对比查询出的密码,密码不正确修改对应的数据的登陆次数
        for (UserInfo info : userInfos) {
            //如果密码不相等,比较次数
            if(!EncryptUtil.getInstance().MD5(passWord).equals(info.getPassWord())){
                //密码不相等,首先将该账号的登陆次数减一
                UserInfo u = new UserInfo();
                u.setUserId(info.getUserId());
                u.setLoginNum(info.getLoginNum()-L_ONE);
                //次数>1表示当前用户此次失败后不会被锁定
                if(info.getLoginNum() > L_ONE){
                    int i = userInfoMapper.updateByPrimaryKeySelective(u);
                    if (i>I_ZERO) {
                        LOGIN_USER_ERROR.setNum(String.valueOf(info.getLoginNum()-L_ONE));
                        return LOGIN_USER_ERROR;
                    }
                }else{
                    //次数<1表示此次失败后,账号将被锁定
                    u.setStatusCd(StatusCdEnum.FROZEN_ENUM.getCode());
                    u.setStatusDate(new Date());
                    int i = userInfoMapper.updateByPrimaryKeySelective(u);
                    if(i>I_ZERO){
                        return LOGIN_USER_NUM;
                    }
                }
            }
        }

        //根据用户名和密码查询数据库
        return UserEnum.SUCCESS;
    }
}

实现类中主要对登陆和注册的相关逻辑操作,这里说下相关逻辑:

注册:界面中只输入用户名和密码,在业务层将必填的字段进行补全,密码进行加密,状态为有效,登陆次数为默认5次,注册时间为当前时间等。
登陆:根据用户名进行数据库的查询(有效的、登陆次数>1),如果查不到,报错返回,如果查到数据则判断查到的密码和输入的密码是否相等,如果相等,通过,如果不相等,则判断登陆次数是否>1,如果大于1则将剩余的次数报错(用户名或密码不正确,剩余次数*次)返回,如果<1则报错返回错误信息(该用户失败次数已达5次,请次日再试)。

接口Service:

public interface UserService {
    /**
     * 根据名称查询user对象
     * @param name 名称
     * @return user对象
     */
    UserInfo findByName(String name);

    List findAll();

    UserInfo findOne(Long id);

    UserInfo save(UserInfo UserInfo);

    UserInfo saveAndUpdate(UserInfo UserInfo);

    void deleteUser(long id);
    UserInfo findById(long id);

    int insert(UserInfo userInfo);

    UserEnum login(UserInfo userInfo);
}

3.5 Controller

这个是业务的controller控制层,也没有什么复杂的逻辑,只需要注意一点就是,如果想要返回到页面中那么controller的注解不能使用@RestController,应该使用@Controller,如果只是返回数据则无所谓。因为@RestController会将返回的结果转换为json串,所以不能返回到页面中。

@Api("用户表操作控制层")
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 根据名称查询
     * @param name 名称
     * @return 返回User对象
     */
    @GetMapping("/user/name")
    @ApiOperation("根据名称查询user对象,JPA版")
    public UserInfo findByName(@RequestParam("name") String name){
        return userService.findByName(name);
    }

    /**
     * 查询所有的user对象
     * @return user列表
     */
    @GetMapping("/user/all")
    @ApiOperation("查询所有的user对象,JPA版")
    public List findAll(){
        return userService.findAll();
    }

    /**
     * 新增
     */
    @PostMapping("/user")
    @ApiOperation("新增user对象,JPA版")
    public UserInfo save(@RequestBody UserInfo userInfo){
        return userService.save(userInfo);
    }

    /**
     * 删除
     */
    @DeleteMapping("/TUserInfo/{id}")
    @ApiOperation("删除user对象,JPA版")
    public void delete(@PathVariable("id") long id){
        userService.deleteUser(id);
    }

    /**
     * 更新
     */
    @PutMapping("/user")
    @ApiOperation("更新user对象,JPA版")
    public UserInfo update(UserInfo userInfo){
        return userService.saveAndUpdate(userInfo);
    }

    /**
     * 通过Id查询
     */
    @RequestMapping("/user/{id}")
    @ApiOperation("查询user对象,JPA版")
    public UserInfo findOne(@PathVariable("id") Long id){
        return userService.findOne(id);
    }

    /**
     * 通过Id查询,MyBatis版
     */
    @GetMapping("/user/mybatis/{id}")
    @ApiOperation("根据Id查询UserInfo对象,Mybatis版")
    public UserInfo findById(@PathVariable Long id){
        return userService.findById(id);
    }

    /**
     * 新增,Mybatis版
     */
    @PostMapping("/user/mybatis")
    @ApiOperation("新增user对象,Mybatis版")
    public int insert(@RequestBody UserInfo userInfo){
        return userService.insert(userInfo);
    }

    @PostMapping("/register")
    @ApiOperation("用户注册")
    public ResultDTO userRegister(UserInfoDTO userInfoDTO){
        UserInfo userInfo = EntityToDTO.INIT.toUserInfo(userInfoDTO);
        int result = userService.insert(userInfo);
        if(result > 0){
            return ResultUtils.SUCCESS();
        }
        return ResultUtils.ERROR();
    }

    @PostMapping("/login")
    @ApiOperation("用户登陆")
    public ResultDTO userLogin(UserInfoDTO userInfoDTO){
        UserInfo userInfo = EntityToDTO.INIT.toUserInfo(userInfoDTO);
        UserEnum result = userService.login(userInfo);
        if(result == UserEnum.SUCCESS){
            return ResultUtils.SUCCESS();
        }
        return ResultUtils.ERROR(result.getCode(),result.getMsg(),result.getNum());
    }
}

这个是视图controller,专门用户视图的跳转

@Api("用于视图转换")
@Controller
@RequestMapping("/view")
public class ViewController {

    /**
     * 进入注册界面
     */
    @GetMapping("/register")
    @ApiOperation("进入用户注册")
    public String enterRegister(){
        System.out.println("进入注册界面...");
        return "index";
    }

}

没有什么复杂的逻辑,这里不赘述。

3.6 html页面

html页面 中采用ajax进行登录和注册的交互,具体的页面如下:

注册和登陆的代码相差无几,这里就只贴注册的代码。

$.ajax({
				type:"POST",
				url:"/user/register",
				data:{
					"userNickName": username,
					"passWord": password
				},
				dataType:"json",
				success:function(dataX){
					console.log("返回的code为:"+dataX.code);
				if(dataX.code === "000000"){
					$("#login-username").val(username);
					$("#login-password").val(password);
					//注册成功
					spop({
						template: '

注册成功

即将于3秒后返回登录', position: 'top-center', style: 'success', autoclose: 3000, onOpen : function(){ var second = 2; var showPop = setInterval(function(){ if(second == 0){ clearInterval(showPop); } $('.spop-body').html('

注册成功

即将于'+second+'秒后返回登录'); second--; },1000); }, onClose : function(){ goto_login(); } }); }else{ alert("注册失败:" + dataX.msg) } }, error:function(jqXHR){ alert("注册异常:"+ jqXHR.statusText); } });

页面效果如下:

3.7 yml文件配置

由于springBoot的结构是在resources目录下有专门的templates文件夹和static文件夹,
templates用于放置一些html页面,static放置一些静态资源,由于SpringBoot会默认访问resources下的这两个文件夹下的html和js、css…文件,关于html和静态资源需要在yml文件中进行路径的配置,否则会访问不到静态资源,这里本人就踩了不少坑。

spring:
  # 配置这个表示访问templates页面路径的前缀
  thymeleaf:
    prefix: classpath:/templates/
    # 访问静态资源的路径,可以是多个,表示请求的静态资源会查找的目录
  resources:
    static-locations:
      classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
  # 访问静态资源的请求方式,就是html请求静态资源的时候需要以static开头
  mvc:
    static-path-pattern: /static/**

3.8 POM文件依赖

这里引用的依赖大多都是直接从maven仓库中找的稳定的新的,需要的可自行去搜索查找,点我



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.3.RELEASE
         
    
    com.example
    demo
    0.0.1-SNAPSHOT
    demo
    Demo project for Spring Boot

    
        1.8
        2.9.2
        2.0.0
        1.2.57
        1.2.0.Final
    

    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-data-jpa
        
        
        
            mysql
            mysql-connector-java
        
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
        
            io.springfox
            springfox-swagger2
            ${swagger.version}
        
        
            io.springfox
            springfox-swagger-ui
            ${swagger.version}
        
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            ${mybatis.version}
        
        
        
            com.alibaba
            fastjson
            ${fastjson.version}
        
        
        
            org.mapstruct
            mapstruct-jdk8
            ${mapstruct.version}
        
        
            org.mapstruct
            mapstruct-processor
            ${mapstruct.version}
            provided
        
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
        
        
            org.springframework.boot
            spring-boot-devtools
            true
            true
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    



        
            
                org.springframework.boot
                spring-boot-maven-plugin
            



            


        
    



**至此从前端到后端使用springboot开发的登陆注册就完成了。**

4. 踩坑秘籍

4.1 xml文件返回结果是list的size为1,但是结果为null

如果数据库表字段和实体的类型匹配不到,在结果返回的时候使用resultType是不能将结果正常的返回出来的,我遇到的情况是查询出数据条数为1,结果的list的size的确是1,但是里面却是null,这个就是因为字段类型不匹配,导致的数据没有被填充到指定的实体中,这个时候应该使用resultMap对表字段和实体字段进行指定。这样就能正常的返回数据了。

4.2 Controller返回到html

如果想要返回到页面中那么controller的注解不能使用@RestController,应该使用@Controller,如果只是返回数据则无所谓。因为@RestController会将返回的结果转换为json串,所以不能返回到页面中。

4.3 关于静态资源的配置

由于springBoot的结构是在resources目录下有专门的templates文件夹和static文件夹,
templates用于放置一些html页面,static放置一些静态资源,由于SpringBoot会默认访问resources下的这两个文件夹下的html和js、css…文件,关于html和静态资源需要在yml文件中进行路径的配置,否则会访问不到静态资源,这里本人就踩了不少坑。

spring:
# 配置这个表示访问templates页面路径的前缀
thymeleaf:
  prefix: classpath:/templates/
  # 访问静态资源的路径,可以是多个,表示请求的静态资源会查找的目录
resources:
  static-locations:
    classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
# 访问静态资源的请求方式,就是html请求静态资源的时候需要以static开头
mvc:
  static-path-pattern: /static/**

4.4 Swagger 配置

swagger需要在pom文件先添加依赖,具体依赖看上面的介绍,然后自定义一个swagger配置类,就可以在Controller中使用了,配置类参考:

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket buildDocket(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(buildApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    public ApiInfo buildApiInfo(){
        return new ApiInfoBuilder()
                .title("SpringBoot配置Swagger文档API")
                .description("简单优雅的RestFun风格")
                .version("1.0")
                .build();
    }
}

4.5 mapstruct的配置和使用

mapstruct的配置我踩坑比较多,最初直接在在maven仓库中搜索找到了依赖直接放进去,写了接口类,发现编译后并不能自动生成实现类。
我在maven仓库下载的是core
SpringBoot写一个登陆注册功能,和期间走的坑_第3张图片
代码执行过程中一直报错,后面在网上查找答案才发现,我引用错依赖了,应该引用下面两个:
SpringBoot写一个登陆注册功能,和期间走的坑_第4张图片
添加完正确的引用后,写一个工具接口类就可以了:
SpringBoot写一个登陆注册功能,和期间走的坑_第5张图片

代码下载地址

如果文章能够看懂,请自行编码,如实在完成不了再下载源码,编码注重的是自己敲代码的过程。下载地址点我

至此文章已全部结束,文章用来记录自己踩过的坑,同时希望能帮助一些人,文章篇幅过长,有问题希望大家指正。我们一起成长!!

你可能感兴趣的:(SpringBoot写一个登陆注册功能,和期间走的坑)