其他分享
首页 > 其他分享> > 小小的项目

小小的项目

作者:互联网

使用Thymeleaf+SpringBoot开发用户管理系统

Spring Boot支持FreeMarker、Groovy、Thymeleaf和Mustache四种模板解析引擎,官方推荐使用Thymeleaf。

口令加密问题

口令解密存放是有必要的,可以避免廉政危机

###加密算法

优点:算法公开、计算量小、加密速度快、加密效率高、可逆

缺点:双方使用相同钥匙,安全性得不到保证

算法: 在对称加密算法中常用的算法有:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK、AES等。相较于DES和3DES算法而言,AES算法有着更高的速度和资源使用效率

需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)

非对称加密中使用的主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等

公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密

非对称密码体制的特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快

对称密码体制中只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全,而非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了

但是RSA加密算法效率较差,对大型数据加密时间很长,一般用于小数据。

不能解密,最常见的算法有MD5、SHA-1等

Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护

是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。

根据输出值,不能得到原始的明文,即其过程不可逆

MD5算法具有以下特点:

1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。

2、容易计算:从原数据计算出MD5值很容易。

3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。

4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被”压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1、RIPEMD以及Haval等。

public class A {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        String ss="123456";
        MessageDigest md=MessageDigest.getInstance("MD5");//参数就是算法名称
        byte[] arr=md.digest(ss.getBytes());//获取原文的数字签名值
        BASE64Encoder encoder=new BASE64Encoder(); //将字节数组转换为可读的字符串
        String target=encoder.encode(arr);
        System.out.println(target);  //4QrcOUm6Wau+VuBX8g+IPg==
        System.out.println(target.length());

        //md5可以采用碰撞算法解密,密文通过碰撞算法可以获取加密结果相关的一个字符串,注意不是原文串
        //解决方案为加盐salt
        String salt= UUID.randomUUID().toString().replace("-","");//永不重复的随机字符串
        arr=md.digest((ss+salt).getBytes());
        target=encoder.encode(arr);
        System.out.println(target);  //0QK01bYzSBmrh6YhFm9XAw==

        //为了进一步提高加密效果,可以进行多次加密计算
        for(int i=0;i<10;i++){
            arr=md.digest((ss+salt).getBytes());
            ss=encoder.encode(arr);
        }
        target=encoder.encode(arr);
        System.out.println(target);  //MXStE9GyPGGoinZ7/twIKw==
    }
}

相关配置

spring:
  datasource:
    druid:   # druid连接池的相关配置
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql:///test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8
      username: root
      password: 123456

  sql:
    init:  # 数据库初始化操作的配置,当应用启动时会自动执行所指定的sql文件
      schema-locations: classpath*:database/schema.sql
      enabled: true

  thymeleaf:   # 关闭Thymeleaf缓存,一般开发时必须关闭,否则修改效果无法立即体现
    cache: false
    
pagehelper:  # 采用插件方式进行物理分页的配置
  helper-dialect: mysql   # 定义数据库平台
  reasonable: true  # 分页参数的合理化处理

惯例优于配置

持久层

参照表结构定义对应的实体类

@Data
@Table(name="t_roles")  //定义对应的表名称
public class Role implements Serializable {
    @Id//用于声明标识属性---主键
    @KeySql(useGeneratedKeys = true) //要求插入数据后应该返回数据表自动生成的id值
    private Long id;
    private String title;
}

继承框架提供的Mapper接口定义对应的Mapper接口

@Repository
public interface RoleMapper extends Mapper<Role> {
}

为了实现系统自动发现Mapper接口,并提供代理实现,所以需要在主类上添加Mapper接口的自动扫描

@MapperScan("com.yan.dao")
@SpringBootApplication
public class Springboot05Application {
    public static void main(String[] args) {
        SpringApplication.run(Springboot05Application.class, args);
    }
}

业务层

Spring要求面向接口编程

定义接口

public interface IUserServ {
    boolean createUser(User user);
}

提供实现类

@Service
public class UserServImpl implements IUserServ{
    @Autowired
    private UserMapper userMapper;
    @Override
    public boolean createUser(User user) {
        int res=userMapper.insertSelective(user);
        return res>0;
    }
}

事务支持

在主类上添加注解,打开注解事务的支持

@EnableTransactionManagement
@SpringBootApplication
public class Springboot05Application {

   public static void main(String[] args) {
       SpringApplication.run(Springboot05Application.class, args);
   }

}

在业务类上添加对应的事务特性说明,Spring提供5方面的特性设置

@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
@Service
public class UserServImpl implements IUserServ{
    @Autowired
    private UserMapper userMapper;
    @Transactional(readOnly = false,propagation = Propagation.REQUIRED)
    public boolean createUser(User user) {
        int res=userMapper.insertSelective(user);
        return res>0;
    }
}

控制器

第一次访问应该是打开输入页

@Controller
public class UserController {
    @Autowired
    private IUserServ userService;
    @RequestMapping(value={"","/","/add"},method = RequestMethod.GET)
    public String add(Model model)throws Exception{
        return "user/add";
    }
}

输入页面

采用模板定义页面,所以页面的存放位置为resources/templates目录下


<html lang="en" xmlns:th="http://www.thymeleaf.org">

####Thymeleaf相关语法

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/hello")
    public String hello(@RequestParam(required = false,defaultValue = "Thymeleaf") String username, Model model){
        String res="Hello "+username+"!";//模拟业务逻辑处理
        model.addAttribute("msg",res);//通过request传递数据到页面
        return "test";
    }
}

模板定义/resources/templates/test.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--这里的th:text中使用的是一个字符串类型的字面量-->
<p th:text="'hello SpringBoot'">hello thymeleaf</p>
<!--通过表达式语言获取控制器传递的数据 -->
<div th:text="${msg}">原始显示内容</div>
</body>
</html>

如果不通过服务器直接访问,则页面会忽略所有的Thymeleaf语法,所以显示原始内容;而通过服务器访问页面时,则thymeleaf生效,会显示这行结果,即th:text中表达式的计算结果

循环操作

1、在控制器中向model中存储集合类型的数据

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/hello")
    public String hello(@RequestParam(required = false,defaultValue = "Thymeleaf") String username, Model model){
        List<Integer> list=new ArrayList<>();
        for(int i=0;i<10;i++)
            list.add(i);
        model.addAttribute("list",list);
        return "test";
    }
}

在模板页中进行循环遍历显示

<div th:each="tt:${list}" th:text="${tt}">原始数据</div>

其中${list}获取数据,each对获取的数据进行遍历,每次获取的元素赋值给tt,再使用text进行显示

在页面种的典型应用

<select id="roleId" name="roleId">
    <option value="">请选择用户身份</option>
    <option th:each="role:${roleList}" th:value="${role.id}" th:text="${role.title}" value="1">选项1</option>
</select>

遍历map的方法

<input type="radio" id="sex" name="sex" value="1" th:each="item:${sexOptions}" th:value="${item.key}" th:text="${item.value}">

客户端数据校验

可以使用jquery-validate库实现

<script src="jslib/jquery.js"></script>
<script src="jslib/jquery.validate.js"></script>
<script>
    $(function(){
        $('#form1').validate({  这里的#form1对应的是输入表单<form id="form1">
            rules:{ 验证规则
                username:{  输入域的名称
                    required:true,
                    rangelength:[6,20],
                    remote:'check'
                }
            },messages:{  本地化的报错信息
                username:{
                    required:'用户名不能空!',
                    rangelength:'用户名称应该在6到20个字符之间',
                    remote:'用户名称已占用!'
                }
            }
        });
    }
</script>

###服务器数据校验
添加依赖

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>

在实体类的属性上添加验证规则

@NotBlank(groups = {UserGroup.AddFirstGroup.class},message = "用户口令不能为空")
@Length(min = 6,max = 20,groups = {UserGroup.AddSecondGroup.class},message = "用户口令应该是6到20个字符之间")
private String password;

在控制器方法上添加注解要求执行服务器端数据校验

@RequestMapping(value="/add",method = RequestMethod.POST)
public String add(@ModelAttribute("user") @Validated(UserGroup.AddGroup.class) User user, Errors errors)throws Exception{
    if(errors.hasErrors())
        return "user/add";
    return "redirect:/login";
}

页面显示报错信息th:errors

<input type="password" id="password" name="password"/>
<span class="fieldError" th:if="${#fields.hasErrors('*{password}')}" th:errors="*{password}"></span>

标签:小小的,加密,String,项目,public,算法,class,MD5
来源: https://blog.csdn.net/lyxnb_/article/details/117566609