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>
简单的主页:
简单的登录:
简单的注册:
最后啦,也不容易,点个小赞吧 !!!
有错大家及时纠正 !!