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

后端服务器有两种主流的形式,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. iOS开发实战之搜索控制器UISearchController使用

    当tableView中的数据过多的时候,在tableView上加一个搜索框就变的很必要了,本文就讨论搜索控制器的使用,以及谓词的简单实现. .m文件中代码如下 添加搜索控制器的各种协议 <UIS ...

  2. 在IntelliJ IDEA中多线程并发代码的调试方法

    通常来说,多线程的并发及条件断点的debug是很难完成的,或许本篇文章会给你提供一个友好的调试方法.让你在多线程开发过程中的调试更加的有的放矢. 我们将通过一个例子来学习.在这里,我编写了一个多线程程 ...

  3. 8道python练习题,能做出来的没几个

    变量的定义 程序就是用来处理数据的,而变量就是用来存储数据的 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道 ...

  4. MarkDown语法的详细使用教程

    MarkDown语法 Markdown是一种纯文本格式的标记语言.通过简单的语法可以使普通文本内容具有一定的格式. 一. 标题 在要设置为标题的文字前面加#和空格 一个#和空格是一级标题,两个##和空 ...

  5. java方法与方法的重载

    一 方法 1.方法的概述 在java中,方法就是用来完成解决某件事情或实现某个功能的办法. 方法实现的过程中,会包含很多条语句用于完成某些有意义的功能——通常是处理文本, 控制输入或计算数值.我们可以 ...

  6. C#LeetCode刷题,走进Google,走近人生

    概述 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/1015 访问. 本系列博文将会向大家展示我在LeetCode上的刷 ...

  7. Scss 定义内层class的简单写法

    如果定义样式的时候,内层样式名称和外层保持一致的话可以简写如下 如果一个样式下有相关的其他样式可以使用 &-xxx 来简写, <template> <div class=&q ...

  8. 关于华为否认HKSP来自官方的一点看法

    今天刷手机,无意看到一则消息: 华为否认提交给 Linux 内核的不安全补丁 HKSP 来自官方 这个消息吸引我的原因有几点: 华为被制裁刚满一年,现在由于新冠疫情影响,感觉又处于很敏感的时期: 华为 ...

  9. JavaScript设计模式之单例模式【惰性单例】

    在提高开发水平,往中高级前端工程师中,利用设计模式是必不可少的一条道路.掌握设计模式的思想远远比硬套重要,因为设计模式是一种思想,不局限于开发语言.但实际上由于语言的特性不同,往往在实现的时候会有不少 ...

  10. SpringSecurity权限管理系统实战—五、整合SpringSecurity(下)

    系列目录 前言 上篇文章SpringSecurity整合了一半,这次把另一半整完,所以本篇的序号接着上一篇. 七.自定义用户信息 前面我们登录都是用的指定的用户名和密码或者是springsecurit ...