上一章讲了表单验证,数据验证和加密。这一章,将研究服务器和数据库的交互过程。

后端服务器有两种主流的形式,SQL数据库和NOSQL数据库。其中MYSQL属于SQL数据库,REDIS属于非SQL数据库。先介绍SQL数据库与服务器的交互过程。

  • 建立数据库表

CREATE TABLE `user_test` (
`id` BIGINT(20) NOT NULL COMMENT '用户ID,手机号码',
`password` VARCHAR(32) DEFAULT NULL COMMENT 'MD5(MD5(pass明文+固定salt) + salt)',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4;

因为是测试,就使用两个字段的用户表。

  • 在配置文件中设置数据库的连接 application.properties文件

#DB Configuration:
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/miaosha?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root

springboot号称一键构建,只需要在配置文件里配置了数据库的连接,不需配置任何bean和类,即可完成数据库的操作,即基于注解的配置,当然数据库的CURD操作也可以在xml的MAPPER里完成,但注解方式更为简单,本项目只采用注解的方式。

  • 在dao包中编写UserMapper类,完成简单的查询操作

@Repository
@Mapper
public interface UserMapper { //根据id查询用户
@Select("select * from user where id = #{mobile}")
@Results(id = "userMap" ,value = {
@Result(id = true,column = "id",property = "mobile"),
@Result(column = "password",property = "password")}
)
public Person userById(String mobile); }
  • 改写UserService类,完成从数据库查询到登录的操作

//3.根据用户手机查询用户
public Person personByMobile(String mobile){
return userMapper.userById(mobile);
}

到目前为止,已经完成了从数据库到服务器的交互过程。但是如果每次查询操作到要与数据库连接,由于延迟,会造成很大的阻塞,因此采用REDIS技术,将数据缓存到内存中,每次查询,只要查缓存中的数据即可,会快很多。


下面研究REDIS技术

使用自带的redis模板,不需要创建redis的配置文件,只需要在application.properties中配置

  • 配置application.properties

#Redis Configuration:
spring.redis.host=localhost
spring.redis.port=6379
  • 需要导入的坐标

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

导入坐标之后,可以对RedisTemplate直接注入,并使用其方法,但RedisTemplate的注入需要注意几点:

1.当private RedisTemplate<String ,String > redisTemplate;时,即key与value都是基础类型时,注入只需要@Autowired即可成功。

但当value值是自己定义的类时,注入需要先将该类序列化,即继承序列化接口,然后使用@Resource注解进行注入。即可成功。

  • 重写UserService类

 public Result login(Person person){
if(person==null){
throw new GobalException(0,"该用户为空");
} String mobile=person.getMobile();
String password=person.getPassword(); //根据id得到数据库用户
Person persondb = personByMobile(mobile);
if(persondb==null){
throw new GobalException(0,"查无此人");
} String dbPassword = persondb.getPassword();
String formPass = Md5Util.dbPass2FormPass(dbPassword); if(!formPass.equals(password)){
throw new GobalException(0,"密码错误");
} return Result.SUCCESS; } //3.根据用户手机查询用户
public Person personByMobile(String mobile){ Person person = redisTemplate.boundValueOps(mobile).get();
if(person!=null){
return person;
}
person=userMapper.userById(mobile);
if(person!=null){
redisTemplate.boundValueOps(mobile).set(person);
}
return person;
}
  • 测试

两次查询,第一次从数据库查询,以后就从缓存上查询。


以上我们的登陆场景的代码差不多分析完了,但为了扩展性,对redis的key值进行分析,在网站的未来,不止有用户,还有商品等各种,对key值得管理,不能随意的取名造成混乱,因此,我们需要抽象出一个专门key的类来。

  • 创建一个key的接口

public interface KeyPrefix {

    int expireSeconds();//过期时间

    String getPrefix();//key值

}
  • 抽象一个key的基本抽象类

public abstract class BasePrefix implements KeyPrefix{

    private int expireSeconds;

    private String prefix;

    public BasePrefix(String prefix){
this(0,prefix);
} public BasePrefix(int expireSeconds,String prefix){
this.expireSeconds=expireSeconds;
this.prefix=prefix;
} public int expireSeconds() {
return expireSeconds;
} public String getPrefix() {
String className=getClass().getSimpleName();
return className+":"+prefix;
}
}

调用getPrefix()即可得到类加上前缀的key值。

  • 创建UserKey值

public class UserKey extends BasePrefix {

    public static final int TOKEN_EXPIRE=3600*24*2;

    public UserKey(int expireSeconds,String prefix) {
super(expireSeconds,prefix);
} public static UserKey token=new UserKey(TOKEN_EXPIRE,"tk"); public static UserKey getById=new UserKey(0,"id");
}

至此,我们创建了一个Key值得抽象功能,如果有商品的数据需要存入Redis,则可以再创建一个GoodKey类即可。

接下来,需要创建一个redis的service类,来对数据进行一定的操作,该服务类需要有复用功能,因此用到泛型的概念,我们要通过key值取到自己想得到的类,那么不能直接存储对象本身,而是将对象序列化为一个字符串(通常是一个json字符串),然后存入redis中,取出后,再还原对象。

  • 创建RedisService

@Service
public class RedisService { @Autowired
private RedisTemplate<String, String> redisTemplate; //1.把字符串转换为bean对象
public static <T> T stringToBean(String str, Class<T> clazz) {
ObjectMapper objectMapper = new ObjectMapper();
T t = null;
if(str==null || str.length()==0){
return t;
}
try {
t = objectMapper.readValue(str, clazz);
} catch (Exception e) {
throw new GobalException(0,"REDIS字符串转换异常");
}
return t;
} //2.将bean对象转换为string
public static <T> String beanToString(T value) {
ObjectMapper objectMapper = new ObjectMapper();
String json = null;
if(value==null){
return json;
}
try {
json = objectMapper.writeValueAsString(value); } catch (JsonProcessingException e) {
throw new GobalException(0,"REDIS字符串转换异常");
}
return json;
} //3.获取对象
public <T> T get(KeyPrefix prefix, String key, Class<T> clazz){
//真正的key
String realKey=prefix.getPrefix()+key;
String str = redisTemplate.opsForValue().get(realKey);
T t = stringToBean(str, clazz);
return t;
} //4.设置对象
public <T> void set(KeyPrefix prefix, String key, T value) {
String str = beanToString(value);
String realKey=prefix.getPrefix()+key; redisTemplate.opsForValue().set(realKey,str);
} //5.判断key值是否存在 public <T> boolean exists(KeyPrefix prefix, String key) { String realKey = prefix.getPrefix() + key;
return redisTemplate.hasKey(realKey);
} //6.增加值
public <T> Long incr(KeyPrefix prefix, String key) {
String realKey = prefix.getPrefix() + key;
return redisTemplate.opsForValue().increment(realKey, 1);
} //7.减少值
public <T> Long decr(KeyPrefix prefix, String key) {
String realKey = prefix.getPrefix() + key;
return redisTemplate.opsForValue().increment(realKey, -1);
} //8.扫描key值
// public List<String> scanKeys(String key) {
//
// } //9.删除key值
public void delete(KeyPrefix prefix, String key) {
String realKey=prefix.getPrefix()+key;
redisTemplate.delete(realKey);
}
}

这里应用了泛型的思想,可以保存任何类型的值,思想是,利用JSON类,将某个实体类转换为JSON字符串,然后将字符串存到REDIS中。


到此为止,登录场景所用到的技术和编码工作全部完成,总结如下;

  1. 抽象:将某些属性抽象出来,可以增加复用性,降低耦合,比如Key类。
  2. 安全:登录时的密码需要加密,然后在网路中传输。
  3. 整合:使用框架提供的工具对MVC进行整合,最终完成项目。

下一章将对登录场景的编码进行进一步改进,包括在页面的验证,返回消息的抽象,以及使用Jedis的原生方法完成Redis的缓存操作。

 
 

java初探(1)之登录终探的更多相关文章

  1. [java初探总结篇]__java初探总结

    前言 终于,java初探系列的学习,要告一阶段了,java初探系列在我的计划中是从头学java中的第一个阶段,知识主要涉及java的基础知识,所以在笔记上实在花了不少的功夫.虽然是在第一阶段上面花费了 ...

  2. [java初探10]__关于数字处理类

    前言 在我们的日常开发过程中,我们会经常性的使用到数字类型的数据,同时,也会有众多的对数字处理的需求,针对这个方面的问题,在JAVA语言中.提供解决方法的类就是数字处理类 java中的数字处理类包括: ...

  3. Java 实现 ssh命令 登录主机执行shell命令

    Java 实现 ssh命令 登录主机执行shell命令 1.SSH命令 SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定:SS ...

  4. java初探(1)之登录再探

    https://www.cnblogs.com/lovejune/p/java_login_1.html 上一章内容搭建起了登录应用场景的环境,模拟实现了登录操作,页面与后端数据的交互过程,使用的是异 ...

  5. java初探(1)之登录总结

    登录总结 前几章总结了登录各个步骤中遇到的问题,现在完成的做一个登录的案例,其难点不在于实现功能,而在于抽象各种功能模块,提高复用性,较低耦合度. 前端页面: 对于前端页面来说,不是后端程序员要考虑的 ...

  6. java初探(1)之登录补充

    在登录之后,可能服务器是分布式的,因此不能通过一个本地的session来管理登录信息,导致登录的信息不能传递,即在这台服务器上可以得到用户登录信息,但在那台就得不到.因此,需要设置分布式的sessio ...

  7. java初探(1)之登录初解

    初识登录 登录的应用场景 登录比较常见,大多数网站都有登录的操作.然后登录本身也从简单到复杂有着漫长的发展历史.本文记录博主对登录的应用场景的剖析,深究不在于学习如何实现,主要关注其编码思想,过程中用 ...

  8. Java简单示例-用户登录、单个页面的增删改查及简单分页

    index.html  -登录->stulist.jsp (index.html传递到LoginServlet,进行登录检测及写入session,NO返回index.html界面,OK 跳转到s ...

  9. jasig CAS 实现单点登录 - java、php客户端登录实现

    jasig CAS项目本身就是一个完整的CAS单点登录服务 1.服务端需要把  认证处理类.用户属性返回值处理类 调整成我们自己处理类即可实现单点登录 2.java客户端需要引入cas-client- ...

随机推荐

  1. 011_go语言中的range遍历

    代码演示 package main import "fmt" func main() { nums := []int{2, 3, 4} sum := 0 for _, num := ...

  2. 37 Reasons why your Neural Network is not working

    37 Reasons why your Neural Network is not working Neural Network Check List 如何使用这个指南 数据问题 检查输入数据 试一下 ...

  3. 你可以 CRUD,但你不是 CRUD 程序员!

    什么是务实 务实程序员他们总是在面临问题时,透过问题看到本质,从具体的场景出发,从大局着想,了解整个问题的来龙去脉,他们会对自己的行为负责,在项目面临问题时,他们不会撒手不管或者任由风险一步步扩大直至 ...

  4. java 用集合完成随机点名器和库存管理案例

    一 随机点名器 1.案例需求 随机点名器,即在全班同学中随机的找出一名同学,打印这名同学的个人信息. 我们来完成随机点名器,它具备以下3个内容: 存储所有同学姓名 总览全班同学姓名 随机点名其中一人, ...

  5. Webpack 定义process.env的时机

    定义 process.env的时机 如果已经提取了公共配置文件 webpack.common.js 分别定义了开发配置webpack.dev.js和生产配置webpack.prod.js 在webpa ...

  6. JS实例-DOM查询

    <!DOCTYPE html><html lang="en"><head> <meta charset="utf-8" ...

  7. windows下的Redis安装:

    windows下的Redis安装: 百度网盘地址:https://pan.baidu.com/s/1yYED2pXLWolPXvWaABtF2Q 提取密码:xshu 1.解压文件并且创建start.b ...

  8. mysql基础测试题

    mysql基础测试题:https://www.cnblogs.com/wupeiqi/articles/5729934.html 如何创建表? 就这样类推?如何提取我们想要的元素呢? 综合提取呢?

  9. 从零开始讲解JavaScript中作用域链的概念及用途

    从零开始讲解JavaScript中作用域链的概念及用途 引言 正文 一.执行环境 二.作用域链 三.块级作用域 四.其他情况 五.总结 结束语 引言 先点赞,再看博客,顺手可以点个关注. 微信公众号搜 ...

  10. linux修改最大的文件描述符(max file descriptors)

    用xshell登录linux系统之后,用命令>ulimit -a 注意到系统模式是1024个 使用>ulimit -n 数量,可临时更改,生效范围为当前会话 永久修改的方法: > v ...