SpringBoot框架实现登录注册ajax

第一篇文章,记录一下!

今天是 2019 / 10 / 23     13:32!

1、项目分析,首先规划开发流程

首先把流程先说一下:

       开发步骤: 持久层 > 业务层 > 控制器 > 前端界面  

如下:
开发的所有类和文件夹,下面详细讲解:

差点忘了发添加的依赖:pom.xml内容

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
   
    <!-- SpringBoot父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.zhang</groupId>
    <artifactId>demo_3</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo_3</name>
    <description>Demo project for Spring Boot</description>

   <!-- java 1.8 版本 -->
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
         <!--  jackson   -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>

       <!-- springboot  - start 启动 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
         <!-- springboot  - tomcat  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        
         <!-- springboot  - start  -  web项目 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
         <!-- springboot  - start  -  test测试类-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!--   mybatis  - start   -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        
         <!--  连接mysql数据库   -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!--  junit测试   ->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        
        <!-- springboot  - test测试类-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    
    <!--  spring Boot的Maven插件Spring Boot Maven plugin  -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、创建数据表

    // 创建数据库user
	CREATE DATABASE user;
	USE user;
	
	//创建数据表users
	CREATE TABLE `users` (
	   `id` int(100) NOT NULL AUTO_INCREMENT COMMENT 'id',
	   `username` char(20) NOT NULL COMMENT '用户名',
	   `password` char(20) NOT NULL COMMENT '密码',
	   PRIMARY KEY (`id`)
	 ) ENGINE=InnoDB DEFAULT CHARSET=utf-8mb4;

数据表创建完成!!

3、先把application.properties配置写全

解释:第一行最后的 Shanghai也可以换成 Chongqing。上海、重庆。
mybatis插件需要标明扫描的是哪里的 xml内容。

   spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-  8&serverTimezone=Asia/Shanghai
   spring.datasource.username=root
   spring.datasource.password=root

   mybatis.mapper-locations=classpath:mappers/*.xml

4、首先第一步,进行持久层开发

1、先编写实体类,User实体类。为com.zhang.demo_3.entity下新建的User实体类!

package com.zhang.demo_3.entity;

import java.util.Objects;

public class User {

     //序列化版本号
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String username;
    private String password;

     //getter和settte方法、tostring 等方法自己写 !!
 
}

2、在com.zhang.demo_3 下添加 mapper 包,添加 UserMapper 接口,为com.zhang.demo_3.mapper下的UserMapper接口。

内容如下:

注意:记得在接口前添加 @Mapper注解,用于表明这是持久层接口!

package com.zhang.demo_3.mapper;
	
import com.zhang.demo_3.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {
    /**
     * 用户添加
     * @param user
     * @return
     */
    Integer insert(User user);

    /**
     * 查找用户名
     * @param username
     * @return
     */
    User findByUsername(String username);

    /** 
     * 根据id查找信息
     * @param id
     * @return
     */
    User findById(Integer id);

}

3、在 resource 目录下添加 mappers 包, 编写 UserMapper.xml 文件,

** 这是 resource目录下的com.zhang.demo_3下的mappers **

内容如下:

注意:resultType为使用的具体实体类,还可以使用 resultMap 作为返回值!

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
	        "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">

<mapper namespace="com.zhang.demo_3.mapper.UserMapper">

    <!--用户添加-->
    <!-- Integer insert(User user) -->
    <insert id="insert" useGeneratedKeys="true"
            keyProperty="id">
        INSERT INTO users(
            id,username,
            password
        )VALUES(
            #{id},#{username},
            #{password}
        )
    </insert>

    <!--查找用户名-->
    <!--User findByUsername(String username)-->
    <select id="findByUsername" resultType="com.zhang.demo_3.entity.User">
        SELECT
            id,username,
            password
        FROM
            users
        WHERE
            username=#{username}
    </select>

    <!-- id查找用户 -->
    <!-- User findById(Integer id) -->
    <select id="findById" resultType="com.zhang.demo_3.entity.User">
        SELECT
            id,username,
            password
        FROM
            users
        WHERE
            id=#{id}
    </select>


</mapper>

5、持久层测试

1、在com.zhang.demo_3下新建mapper包,并添加UserMapperTest测试类。

解释:
这是测试mapper包下的 UserMapper接口和 UserMapper.xml是否能连接数据库进行查询 !!

	package com.zhang.demo_3.mapper;
	
	import com.zhang.demo_3.entity.User;
	import org.junit.Test;
	import org.junit.runner.RunWith;
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.boot.test.context.SpringBootTest;
	import org.springframework.test.context.junit4.SpringRunner;
	
	@SpringBootTest
	@RunWith(SpringRunner.class)
	public class UserMapperTest {
	
	    @Autowired(required=true)
	    private UserMapper userMapper;
	  
	   //测试添加数据
	    @Test
	    public void insert(){
	        User user=new User();
	        String username="zhangsan";
	        String password="123456";
	        Integer id=2;
	        user.setId(id);
	        user.setPassword(password);
	        user.setUsername(username);
	        Integer rows=userMapper.insert(user);
	        System.out.println(rows);
	    }
	   //测试查找用户名
	    @Test
	    public void findByUsername(){
	        String username="zhangsan";
	        User result=userMapper.findByUsername(username);
	        System.out.println(result);
	    }
	   //测试根据id查找内容
	    @Test
	    public void findById(){
	        Integer id=4;
	        User result=userMapper.findById(id);
	        System.out.println(result);
	    }
	
	}

查找用户名
只列举了一个。。有问题可以下方提问 !

这样持久层就完成了 !!开发业务层

6、业务层开发

(a) 规划异常

ServiceException :异常基类,便于后继处理!

package com.zhang.demo_3.service.ex;

public class ServiceException extends RuntimeException{

    public ServiceException() {
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(Throwable cause) {
        super(cause);
    }

    public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

UsernameDuplicateException:检查用户名是否被占用,占用已注册!

	package com.zhang.demo_3.service.ex;
	
	public class UsernameDuplicateException extends ServiceException {
	
	    public UsernameDuplicateException() {
	    }
	
	    public UsernameDuplicateException(String message) {
	        super(message);
	    }
	
	    public UsernameDuplicateException(String message, Throwable cause) {
	        super(message, cause);
	    }
	
	    public UsernameDuplicateException(Throwable cause) {
	        super(cause);
	    }
	
	    public UsernameDuplicateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
	        super(message, cause, enableSuppression, writableStackTrace);
	    }
	}

UsernameNotFoundException :用户名找不到,不可以登陆 !

package com.zhang.demo_3.service.ex;

public class UsernameNotFoundException extends ServiceException  {

public UsernameNotFoundException() {
}

public UsernameNotFoundException(String message) {
    super(message);
}

public UsernameNotFoundException(String message, Throwable cause) {
    super(message, cause);
}

public UsernameNotFoundException(Throwable cause) {
    super(cause);
}

public UsernameNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
    super(message, cause, enableSuppression, writableStackTrace);
    }
}

PasswordNotException :密码找不到,密码错误 !

package com.zhang.demo_3.service.ex;

public class PasswordNotException extends ServiceException{
    public PasswordNotException() {
}

public PasswordNotException(String message) {
    super(message);
}

public PasswordNotException(String message, Throwable cause) {
    super(message, cause);
}

public PasswordNotException(Throwable cause) {
    super(cause);
}

public PasswordNotException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
    super(message, cause, enableSuppression, writableStackTrace);
}

}

(b) 接口与抽象方法

1、创建 com.zhang.demo_3.service.IUserService业务层接口,并在接口中添加功能的抽象方法,关于业务层的抽象方法的设计原则:

返回值:仅以操作成功(例如注册成功,登录成功等)为前提来设计返回值;

方法名:自定义;

参数列表:控制器可提供的,通常是用户提交的数据,及Session中的数据;

抛出异常:所有操作失败(登录时用户名不存在,登录时密码错误,注册时用户名被占用等)对应的异常。

基于以上设计原则,此次“注册”的抽象方法应该是:在com.zhang.demo_3下新建service包,IUserService接口

解释:
这是一个业务层接口。

package com.zhang.demo_3.service;

import com.zhang.demo_3.entity.User;

public interface IUserService {

    /**
     * 用户注册
     * @param
     * @return
     */
    void reg(User user);

    /**
     * 用户登录
     * @param user
     * @return
     */
    User login(String username, String password);
    
}

© 实现业务
进行编写业务层实现类,在com.zhang.demo_3.service下新建一个包impl,用于存放业务层实现类。这里新建一个UserServiceImpl实现类!

注意:记得添加@Service注解,在类中声明持久层对象。

package com.zhang.demo_3.service.impl;

import com.zhang.demo_3.entity.User;
import com.zhang.demo_3.mapper.UserMapper;
import com.zhang.demo_3.service.IUserService;
import com.zhang.demo_3.service.ex.UsernameNotFoundException;
import com.zhang.demo_3.service.ex.PasswordNotException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServieImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    //用户注册业务逻辑
    @Override
    public void reg(User user) {
        System.out.print(user.getUsername());
        System.out.print(user.getPassword());
        //判断用户名是否为null
        String username = user.getUsername();
        User result = userMapper.findByUsername(username);

        if(result != null){
            throw new UsernameNotFoundException("注册名被占用");
        }

        String password=user.getPassword();
        user.setUsername(username);
        user.setPassword(password);


        System.out.print(result);

        userMapper.insert(user);
    }
    
   //用户登录业务逻辑
    @Override
    public User login(String username, String password) {
        User result=userMapper.findByUsername(username);

        if(result == null){
             throw new UsernameNotFoundException("用户名不存在");
        }

        if(!password.equals(result.getPassword())){
            throw new PasswordNotException("密码错误");
        }

        User user =new User();
        user.setUsername(username);
        user.setPassword(password);

        return user;
    }
}

6、业务层测试

1、在 test测试下 com.zhang.demo_3下新建service包,然后建立 UserServiceTest测试类,
内容如下:

package com.zhang.demo_3.service;

import com.zhang.demo_3.entity.User;
import com.zhang.demo_3.mapper.UserMapper;
import com.zhang.demo_3.service.ex.ServiceException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTest {

    @Autowired
    private IUserService userService;

    @Test
    public void reg(){
        User user=new User();
        String username="zhang";
        String password="123456";
        Integer id=3;
        user.setId(id);
        user.setPassword(password);
        user.setUsername(username);
        userService.reg(user);

    }

    @Test
    public void login(){
         try {
            String username="root";
            String password ="1234";
            User Result=userService.login(username, password);
            System.err.println(Result);

           } catch (ServiceException e) {
            System.err.println(e.getClass().getName());
            System.err.println(e.getMessage());
          }
    }
}

业务层开发完成,进入控制器开发步骤:

业务层测试失败:
在这里插入图片描述
业务层登录测试成功:
在这里插入图片描述

7、控制器代码编写

(a) 处理异常
先创建cn.tedu.store.util.JsonResult响应结果类型,并在其中声明需要它可以给客户的数据的属性:

package com.zhang.demo_3.util;

public class JsonResult<T> {

    private Integer state;
    private T data;
    private String message;

    public JsonResult() {
        super();
    }

    /**
     * 返回异常信息
     * @param e
     */
    public JsonResult(Throwable e){
         this.message=e.getMessage();
    }

    /**
     * 返回状态码和data响应数据类型
     * @param state
     * @param data
     */
    public JsonResult(Integer state, T data) {
        this.state = state;
        this.data = data;
    }

    public JsonResult(Integer state, String message) {
        this.state = state;
        this.message = message;
    }

    public JsonResult(Integer state) {
        this.state = state;
    }
    
    //getter和setter方法。。。。
    
}

此次“注册”时,业务层的“注册”功能可能抛出UsernameDuplicateException或InsertException,这2种异常其实也不只是“注册”才会抛出,其它的某些功能也可能抛出同样的异常,SpringMVC框架提供了统一处理异常的机制,在编写控制器中处理请求的代码时,就不必再关注异常的问题,等同于控制器中处理请求时将异常抛出,由SpringMVC框架再去捕获相关异常,并进行处理即可!

可以在控制器中添加一个专门处理异常的方法,关于方法的设计原则:

权限:应该使用public权限;
返回值:使用与处理请求的方法相同的原则;
方法名称:自定义;
参数列表:至少包括1个异常类型的参数,表示将捕获并处理的异常,另外,根据需要,可以添加HttpServletRequest等参数,但是,并不能像处理请求的方法那样随意添加;
必须添加@ExceptionHandler注解。

所以,处理异常的方法的声明大致是:

@ExceptionHandler
public JsonResult<Void> handleException(Throwable ex) {

}

在com.zhang.demo_3下添加 controller包,创建com.zhang.demo_3.controller.BaseController,实现Serializable接口,将作为实体类的基类,由于该类不需要直接创建对象,其存在的价值就是被其它实体类继承,所以,应该使用默认权限,且使用abstract进行修饰:

以上方法必须在控制器类中,也只能作用于当前控制器类中处理请求时抛出的异常,为了使得所有控制器类抛出的异常都可以被处理,应该将以上处理异常的代码添加在控制器类的基类BaseController中:

package com.zhang.demo_3.controller;

import com.sun.org.apache.xml.internal.resolver.helpers.PublicId;
import com.zhang.demo_3.service.ex.PasswordNotException;
import com.zhang.demo_3.service.ex.ServiceException;
import com.zhang.demo_3.service.ex.UsernameDuplicateException;
import com.zhang.demo_3.service.ex.UsernameNotFoundException;
import com.zhang.demo_3.util.JsonResult;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

/**
 * 控制器基类
 */
public abstract class BaseController {

    /**
     * 返回成功状态码2000
     */
    public static final int SUCCESS=2000;

    @ExceptionHandler({ServiceException.class, FileUploadException.class})
    public JsonResult<Void> handleException(Throwable ex) {
    
        JsonResult<Void> jsonResult=new JsonResult<>(ex);

        if(ex instanceof UsernameDuplicateException){
             //用户名被占用  -  2002
             jsonResult.setState(2002);
        }else if(ex instanceof UsernameNotFoundException){
             //用户名找不到  -  2003
             jsonResult.setState(2003);
        }else if(ex instanceof PasswordNotException){
             //密码错误
             jsonResult.setState(2004);
        }
        //返回响应值
        return jsonResult;
	   }
}

如果不通过基类处理异常,也可以自定义某个类,在类之前添加@ControllerAdvice或@RestControllerAdvice也可以使得整个项目的所有控制器都应用该处理异常的做法!

编写UesrController类,创建com.zhang.demo_3.controller.UserController类。

注意:@RestController 必须写,里边有PostMapping和RequestMapping();
声明@Autowired private IUserService userService;业务层对象

	package com.zhang.demo_3.controller;
	
	import com.zhang.demo_3.entity.User;
	import com.zhang.demo_3.service.IUserService;
	import com.zhang.demo_3.util.JsonResult;
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.web.bind.annotation.PostMapping;
	import org.springframework.web.bind.annotation.RequestMapping;
	import org.springframework.web.bind.annotation.RestController;
	
	import javax.servlet.http.HttpSession;
	
	@RestController
	@RequestMapping("users")
	public class UserController extends BaseController{
	
	    @Autowired
	    private IUserService userService;
	
	    @PostMapping("reg")
	    public JsonResult<Void> reg(User user)  {
	        userService.reg(user);
	        return new JsonResult<>(SUCCESS);
	    }
	
	    @RequestMapping("login")
	    public JsonResult<User> login(String username, String password, HttpSession session){
	        User data = userService.login(username,password);
	        session.setAttribute("uid",data.getId());
	        session.setAttribute("username",data.getUsername());
	
	        return new JsonResult<>(SUCCESS,data);
	    }
	}

完成后,可以通过http://localhost:8080/users/reg?username=json&password=1234进行测试注册。

上边我写的@PostMapping,不可以用这个网址测试。
可以改为@RequestMapping,进行测试。
如下:
在这里插入图片描述

8、前端展示

register注册界面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    <script src="jquery-3.4.1.min.js"></script>
</head>
<body>
<form id="form-reg">
    <center>
        <tr>
            <td><input type="text" id="username" name="username"></td><br>
            <td><input type="password" id="password" name="password"></td><br>
            <td><input type="button" value="注册" id="btn-reg"></td>
            <a href="login.html">没有账号,进入登录界面</a>
        </tr>
    </center>
</form>

<script type="text/javascript">
    $("#btn-reg").click(function() {
        // alert("准备注册!");
        $.ajax({
            "url":"/users/reg",
            "data":$("#form-reg").serialize(),
            "type":"post",
            "dataType":"json",
            "success":function (json) {
                if (json.state == 2002) {
                    alert("注册失败:"+json.message);
                } else {
                    alert("注册成功:");
                    location.href="index.html";
                }
            }
        });
    });
</script>

</body>
</html>
login注册界面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    <script src="jquery-3.4.1.min.js"></script>
</head>
<body>
<form id="form-login">
    <center>
        <tr>
            <td><input type="text" id="username" name="username"></td><br>
            <td><input type="password" id="password" name="password"></td><br>
            <td><input type="button" value="登录" id="btn-login"></td>
            <a href="register.html">已有账号,进入注册界面</a>
        </tr>
    </center>
</form>

<script type="text/javascript">
    $("#btn-login").click(function() {
        // alert("准备注册!");
        $.ajax({
            "url":"/users/login",
            "data":$("#form-login").serialize(),
            "type":"get",
            "dataType":"json",
            "success":function (json) {
                if (json.state == 2004) {
                    alert("登录失败:"+json.message);
                } else {
                    alert("登录成功:");
                    location.href="index.html";
                }
            }
        });
    });
</script>

</body>
</html>
index主页
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
<a href="register.html">zhuce</a>
<a href="login.html">denglu</a>


</body>
</html>

简单的主页:
在这里插入图片描述
简单的登录:
在这里插入图片描述
简单的注册:
在这里插入图片描述

最后啦,也不容易,点个小赞吧 !!!
有错大家及时纠正 !!

发布了9 篇原创文章 · 获赞 15 · 访问量 489

猜你喜欢

转载自blog.csdn.net/weixin_45395031/article/details/102699684