demo_2
业务层
1 package com.demo.service; 2 3 import com.demo.pojo.User; 4 5 public interface IUserService { 6 /** 7 * 用户登录 8 * @param user 用户信息 9 * @return 返回数据 10 */ 11 User reg(User user); 12 }
实现类
创建`com.demo.service.Impl.UserServiceImpl`类,使用`@Service("userService")`对类注解,声明`private UserMapper userMapper`成员,并使用`@Autowired`注解,实现`IUserService`,实现抽象方法:
1 package com.demo.service.Impl; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 import com.demo.dao.UserMapper; 7 import com.demo.pojo.User; 8 import com.demo.service.IUserService; 9 10 //实现类 11 @Service("userService") 12 public class UsertServiceImpl implements IUserService{ 13 @Autowired 14 private UserMapper userMapper; 15 16 public User reg(User user) { 17 userMapper.insert(user); 18 return user; 19 } 20 21 }
在业务层,关于操作的成功与否,推荐:只要能把方法顺利执行结束,就是成功,如果中途出错,则抛出异常,后续,方法的调用者(控制器层的某个方法)通过try...catch来处理。
## 关于密码
1 package 测试; 2 3 import java.util.UUID; 4 5 import org.springframework.util.DigestUtils; 6 7 public class 设计密码 { 8 public static void main(String[] args) { 9 //文摘 10 System.out.println("Digest"); 11 //密码 12 String[] password = {"123456","000000","654321"}; 13 UUID salt = UUID.randomUUID();//随机盐 14 System.out.println(salt.toString().length());//长度 15 for (int i = 0; i < password.length; i++) {//双重加盐 16 String md5Str = DigestUtils.md5DigestAsHex(password[i].getBytes()); 17 md5Str = DigestUtils.md5DigestAsHex((salt+md5Str).getBytes()); 18 System.out.println(md5Str.toUpperCase()); 19 } 20 } 21 }
## 查询用户信息--持久层
实现根据用户名查询用户信息,所以,在`UserMapper`接口中添加新的抽象方法:
1 /** 2 * 查询用户信息 3 * @param where WHERE子句,不要包含WHERE关键字 4 * @param orderBy OrderBy子句,不要包含Order By关键字 5 * @param offset 偏移量,用于Limit子句的第一个值 6 * @param countPerPage 每页显示的数据量,用于Limit子句的第二个值,仅当参数offset有效时,该参数才有效,如果没有提供offset值,则该参数没有意义 7 * @return 配置的用户信息的集合 8 */ 9 List<User> select ( 10 @Param("where") String where, 11 @Param("orderBy") String orderBy, 12 @Param("offset") Integer offset, 13 @Param("countPerPage") Integer countPerPage 14 );
然后,在`UserMapper.xml`中添加映射:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" 3 "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> 4 5 <!-- namespace:匹配的接口 --> 6 <mapper namespace="com.demo.dao.UserMapper"> 7 8 9 <!-- 查询用户信息 --> 10 <!-- List<User> select( 11 @Param("where") String where, 12 @Param("orderBy") String orderBy, 13 @Param("offset") Integer offset, 14 @Param("countPerPage") Integer countPerPage); 15 --> 16 <select id="select" resultType="com.demo.pojo.User"> 17 SELECT 18 id,username,password,gender,phone,email,uuid, 19 created_user AS createdUser, 20 created_time AS createdTime, 21 modified_user AS modifiedUser, 22 modified_Time AS modifiedTime 23 FROM 24 t_user 25 <if test="where != null"> 26 WHERE ${where} 27 </if> 28 <if test="orderBy != null"> 29 ORDER BY ${orderBy} 30 </if> 31 <if test="offset != null"> 32 LIMIT ${offset},${countPerPage} 33 </if> 34 </select> 35 </mapper>
##SQL语句中#{ }和${ }的区别
#将传入的数据都当成字符串,会对自动传入的数据加一个双引号。如:order by #{user_id},如果传入的值是123,那么解析成SQL时的值为order by "123",如果传入的值是id,则解析成的SQL为order by "id"。
$将传入的数据直接显示生成在SQL中。如:order by ${user_id},如果传入的值是123,那么解析成SQL时的值为order by user_id,如果传入的值是id,则解析成的SQL为order by id。
#方式能够很大程度防止sql注入;$方式无法防止Sql注入。
$方式一般用于传入数据库对象,例如传入表名。
一般能用#的就别用$。MyBatis排序时使用order by 动态参数时需要注意,用$而不是#。
默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速也是首选做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。
比如,像ORDER BY,你可以这样来使用:
ORDER BY ${columnName};
这里MyBatis不会修改或转义字符串。
接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。
## 查询用户信息--业务层
在业务层接口`IUserService`接口中添加抽象方法:
1 package com.demo.service; 2 3 import com.demo.pojo.User; 4 5 //业务层 6 public interface IUserService { 7 8 /** 9 * 根据用户名查询信息 10 * 11 * @param username 用户名 12 * @return 用户信息,如果没有匹配的用户信息,则返回null 13 */ 14 User findUserByUsername(String username); 15 16 /** 17 * 获取加密的密码 18 * 19 * @param password 明文密码 20 * @param salt 盐 21 * @return 密文密码 22 */ 23 String getEncrpytedPassword(String password, String salt); 24 }
## 在实现类`UserServiceImpl`中实现以上方法(更新注册方法--业务层逻辑):
1 package com.demo.service.Impl; 2 3 import java.util.Date; 4 import java.util.List; 5 import java.util.UUID; 6 7 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.stereotype.Service; 9 import org.springframework.util.DigestUtils; 10 11 import com.demo.dao.UserMapper; 12 import com.demo.pojo.User; 13 import com.demo.service.IUserService; 14 import com.demo.service.ex.UsernameConflictException; 15 16 //实现类 17 @Service("userService") 18 public class UsertServiceImpl implements IUserService { 19 @Autowired 20 private UserMapper userMapper; 21 22 public User reg(User user) { 23 //根据尝试注册的用户名进行查询 24 User u = findUserByUsername(user.getUsername()); 25 //判断用户名是否被占用 26 if (u !=null) { 27 //用户名被占用,则: 28 throw new UsernameConflictException("用户名" + user.getUsername() + "已经被注册!"); 29 } else { 30 //用户名没有被占用,则执行注册相关任务 31 //把密码加密 32 String salt = UUID.randomUUID().toString().toUpperCase(); 33 String md5Password = getEncrpytedPassword(user.getPassword(), salt); 34 user.setPassword(md5Password); 35 //保存uuid,即盐 36 user.setUuid(salt); 37 //保存日志信息 38 Date now = new Date(); 39 user.setCreatedUser("System"); 40 user.setCreatedTime(now); 41 user.setModifiedUser("System"); 42 user.setModifiedTime(now); 43 //使用Mybatis处理insert后 44 //数据的id将被封装到参数对象中 45 //在执行以下代码之前,参数user中并没有id 46 //执行完后,Mybatis将把id封装到参数对象user中 47 userMapper.insert(user); 48 return user; 49 } 50 } 51 52 public User findUserByUsername(String username) { 53 // 确定WHERE子句的内容 54 String WHERE = "username='" + username + "'"; 55 // 调用持久层对象执行查询 56 List<User> users = userMapper.select(WHERE, null, null, null); 57 // 判断查询结果 58 if (users.size() == 0) { 59 // 没有找到数据,则用户名不存在 60 return null; 61 } else { 62 // 找到数据,由于用户名唯一 63 // 则集合中的第一个元素就是要查询的数据 64 return users.get(0); 65 } 66 } 67 68 public String getEncrpytedPassword(String password, String salt) { 69 // 把密码与盐拼接起来 70 String str = password + salt; 71 // 获取拼接后的字符串的消息摘要 72 String md5 = DigestUtils.md5DigestAsHex(str.getBytes()).toUpperCase(); 73 // 返回摘要字符串,即密文 74 return md5; 75 } 76 77 }