目录
1.1、导入咋们的包
<!--导包-->
<!--
<scope>provided</scope>: provided:这一句话表示的意思是 我们的Tomcat中已经存在这个包了 这个项目在
运行打包的时候这个包呢就不需要打了
-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<!--动态生成getter和setter方法的 全参无参构造器的 toString
在使用的时候
@Data
@Allxxxx
@Noxxxx
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--导入数据库的驱动
简单的说就是JDBC的实现类
-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!--这个是Druid的包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--下面导入dbutils这个包-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
1.2、编写登陆的Servlet
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
/**
* 登陆的逻辑
* 1、接受前端传过来的用户名和密码
* 2、通过用户名查询用户对象(去数据库进行查询)
* 3、没有找到 :说明用户名有误
* 4、找到了 那么比较密码是否一致
* 密码不一致 那么说明 密码有误
* 密码一致 那么说明用户身份合法
* 5、用户身份合法 那么生成唯一的标识 token(实际上就是一个字符串)
* 6、将用户身份唯一的标识 存储到数据库 中
* 7、将身份唯一的标识 和用户数据非密码传输到 前端页面进行保存
* 8、前端在请求资源的时候 只需要带上令牌token就可以请求资源
*/
try {
//第一步:解决编码问题
req.setCharacterEncoding("UTF-8");
//第二步:获取前端传递过来的数据
User user = ObjectUtils.getInstance().getParameterObject(req, User.class);
if(null==user || StringUtils.isEmpty(user.getUserName()) || StringUtils.isEmpty(user.getPassword())){
//这里的需错误的状态吗 和 错误的信息 是不能直接在这里写死的
//你先过一个问题没有 如果是我们的状态码后来觉得 需要修改 那不是你还要改源码? 是不利于你维护这个错误信息
throw new BusinessException(ResponceCode.PARAMETER_ERROR.getCode(),ResponceCode.PARAMETER_ERROR.getMessage());
}
//第三步:通过用户名去查询用户对象
User queryUser = JdbcUtils.queryRunner().query("select * from t_user where userName=?", new BeanHandler<User>(User.class), user.getUserName());
if(null==queryUser){
throw new BusinessException(ResponceCode.USERNAME_ERROR.getCode(),ResponceCode.USERNAME_ERROR.getMessage());
}
//执行到这里 说明咋们的用户名是对的 那么比较密码是否一致
if(!StringUtils.equals(user.getPassword(),queryUser.getPassword())){
throw new BusinessException(ResponceCode.PASSWORD_ERROR.getCode(),ResponceCode.PASSWORD_ERROR.getMessage());
}
//执行到这里 说明密码是对的
//生成token 这个token就是用户身份唯一的标识 只要唯一就可以了
String token = TokenUtils.getToken();
//将这个信息 更新到数据库中(目前我们用的是数据库)
JdbcUtils.queryRunner().update("update t_user set token=? where userName=?",token,user.getUserName());
//执行到这里说明更新完成
//首先将密码信息置空
queryUser.setPassword("");
//将token信息设置到用户对象
queryUser.setToken(token);
//封装返回的对象
DataResult<User> userDataResult = new DataResult<>(queryUser);
//再将这个对象呢?转换成json格式
String jsonString = JSON.toJSONString(userDataResult);
//最终进行数据的返回
//设置编码 放置返回的数据有错误
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.write(jsonString);
writer.flush();
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1.3、编写结果集封装的这样一个接口
public interface IResponseCode { //这个是获取错误的信息 String getMessage(); //获取状态码 int getCode(); }
1.4、编写结果集封装的这样一个枚举
/**
* @author xiaobobo
* @title: ResponceCode
* @projectName cd2106projectparent
* @description: 这个就是响应的错误或者正确信息的实例
* @date 2021/8/1610:12
*/
public enum ResponceCode implements IResponseCode{
SUCESS(0,"请求成功"),
PARAMETER_ERROR(100,"参数异常"),
USERNAME_ERROR(101,"用户名不对"),
PASSWORD_ERROR(102,"密码不对"),
SQL_ERROR(103,"SQL异常");
ResponceCode(int code,String message){
this.code=code;
this.message=message;
}
private int code;
private String message;
@Override
public String getMessage() {
return message;
}
@Override
public int getCode() {
return code;
}
}
1.5、编写结果集封装的返回对象
@Data
public class DataResult<T> {
private static int code;
private static String message;
private T t;
public DataResult(){
this.code=ResponceCode.SUCESS.getCode();
this.message=ResponceCode.SUCESS.getMessage();
}
public DataResult(int code,IResponseCode responseCode,T t){
this.code=responseCode.getCode();
this.message=responseCode.getMessage();
this.t=t;
}
public DataResult(int code,ResponceCode responseCode,T t){
this.code=responseCode.getCode();
this.message=responseCode.getMessage();
this.t=t;
}
public DataResult(T t){
this.code=ResponceCode.SUCESS.getCode();
this.message=ResponceCode.SUCESS.getMessage();
this.t=t;
}
public static void success(){
code=ResponceCode.SUCESS.getCode();
message=ResponceCode.SUCESS.getMessage();
}
}
1.6、编写Java的实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String userName;
private String password;
private String token;
}
1.7、编写业务异常
@Data
public class BusinessException extends RuntimeException {
//返回的状态码(很多很多 表示的是成功 或者失败)
private int code;
//如果返回的错误那么这里返回的是错误的原因
private String message;
public BusinessException(int code,String message){
super(message);
this.code=code;
this.message=message;
}
}
1.8、编写JDBC的工具类
public class JdbcUtils {
private static DruidDataSource dataSource=null;
static {
dataSource=new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///cd2106?useUnicode=true&characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("root");
}
/**
* 获取操作数据库的对象
* @return
*/
public static QueryRunner queryRunner(){
return new QueryRunner(dataSource);
}
}
1.9、编写请求参数封装的这样一个工具类
public class ObjectUtils {
private static ObjectUtils objectUtils=new ObjectUtils();
private ObjectUtils(){
}
/**
* 返回这个请求的参数封装成的Java对象
* @param httpServletRequest
* @param clazz
* @param <T>
* @return
*/
public <T> T getParameterObject(HttpServletRequest httpServletRequest,Class<T> clazz) throws IllegalAccessException, InstantiationException, InvocationTargetException {
//这个就是需要封装的Java的类的实例对象
T t=clazz.newInstance();
//接下来需要将请求的参数封装到这个实例对象中
// httpServletRequest.getParameterMap() :是将前端传递的参数的map获取出来
BeanUtils.populate(t,httpServletRequest.getParameterMap());
return t;
}
/**
* 获取当前类的实例
* @return
*/
public static ObjectUtils getInstance(){
return objectUtils;
}
}
1.10、编写token生成的工具类
public class TokenUtils {
/**
* 这个就是生成token的地方
* 这个加锁的目的 是为了防止并发的时候 生成的UUID一致
*
* synchronized:Java中的锁 可以分成两类
* 一类:隐式锁
* 加锁和解锁的过程是由JVM来完成的
* 二类:显示锁
* 加锁和解锁 是自己调用方法来完成的
*
* @return
*/
public synchronized static String getToken() {
String s = UUID.randomUUID().toString();
return s;
}
}