1.创建Spring Boot+Mybatis的maven项目
- 在IDEA中点击File——New——Project新建项目,选择好jdk后点击next:

- 在此页面可以修改项目的信息,默认信息如下:

- 点击next到勾选依赖页面,勾选
web、mysql、jdbc、mybatis如下:


- 点击next后填写项目名称,点击Finish创建完成,等待maven下载依赖包完成,项目结构如下:

-
可以看到maven的
pom.xml文件中已经添加了刚才勾选的web、mysql、jdbc、mybatis依赖,内容如下:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> -
创建数据库,例子中数据库名称为
demo:

- 在
resources下的application.properties中配置数据库连接参数:#数据库连接 spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=你的密码 spring.datasource.driver-class-name=com.mysql.jdbc.Driver - 增加
IndexController和index.html页面:

@Controller
public class IndexController {
@GetMapping("/")
public String index() {
return "index";
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
访问成功
</body>
</html>
-
注意:如果你的
controller和启动类Application不在同一包下,则需要@ComponentScan注解来指定需要加载的bean路径。 -
因为页面放到了
templates下,所以需要在pom.xml文件中加入thymeleaf依赖包:<!--thymeleaf依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> -
到此项目就创建完成。启动项目,访问
localhost:8080,成功页面如下:

2.Spring Security配置
2.1 使用Spring Security原生的页面登录
-
在
pom.xml文件中加入Spring Security依赖包:<!--security依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> -
此时
Spring Security已经生效。如果重新启动项目,访问localhost:8080,会重定向到localhost:8080/login页面,这是Spring Security自带的登录页面,如下:

- 默认的用户名为
user,密码会在启动项目时输出到控制台:

- 输入用户名和控制台打印的密码,登录成功即可跳转到首页。
2.2 通过配置,使用自定义的页面登录
- 增加
LoginController和login.html页面:

@Controller
public class LoginController {
@GetMapping("/login")
public String login(){
return "login";
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>登录</title>
</head>
<body>
<div id="login-box">
<form th:action="@{/login}" method="post">
帐号:<input type="text" name="username">
<br/>
密码:<input type="password" name="password">
<br/>
<button type="submit">登录</button>
<span th:if="${param.error}">登录失败</span>
<span th:if="${param.logout}">退出登录成功</span>
</form>
</div>
</body>
</html>
-
修改
index.html页面,加入退出登录按钮:<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> 访问成功 <a th:href="@{/logout}">点击退出登录</a> </body> </html> -
添加
CustomUserService并实现UserDetailsService,用于根据表单提交的用户名加载对应的用户信息(后续改为从数据库加载用户):

public class CustomUserService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) {
//添加用户的角色,用于权限验证
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
//创建用户:用户名user,密码123,角色ADMIN
return new User("user", this.passwordEncoder.encode("123"), authorities);
}
}
- 增加
WebSecurityConfig配置类,继承WebSecurityConfigurerAdapter来配置访问规则:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//用于密码加密
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//将CustomUserService注册为bean
@Bean
public CustomUserService customUserService() {
return new CustomUserService();
}
//使用自定义的CustomUserService加载用户
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(this.customUserService());
super.configure(auth);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login")//设置登录页面
.loginProcessingUrl("/login")//自定义的登录接口
.failureUrl("/login?error")//登录失败的页面
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()//设置不需要登陆就能访问登录页面
.anyRequest()//登录后可以访问所有页面
.authenticated()
.and()
.csrf().disable();//关闭csrf防护
}
}
- 到此使用自定义页面登录就配置成功了,重启项目,此时
localhost:8080/login显示的是自定义的登录页面:

- 输入用户名user,密码123即可登录成功:

2.3 配置Mybatis动态查询数据库的用户和角色
-
数据库中创建表
sys_user、sys_role、sys_user_role,用来记录用户、角色、用户和角色的关系:CREATE TABLE `sys_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_name` varchar(16) DEFAULT NULL, `password` varchar(128) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; CREATE TABLE `sys_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(16) DEFAULT NULL COMMENT '角色名称', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; CREATE TABLE `sys_user_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_id` bigint(20) DEFAULT NULL, `role_id` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; -
手动在表中添加数据:
-
sys_user表,注意:密码是用new BCryptPasswordEncoder().encode("123")加密后的数据。

sys_role表。

sys_user_role表。

-
在
resources下的application.properties中开启驼峰映射:#数据库连接 spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=你的密码 spring.datasource.driver-class-name=com.mysql.jdbc.Driver #驼峰映射 mybatis.configuration.map-underscore-to-camel-case=true -
驼峰映射就是将数据库中的
xxx_yyy字段映射为实体类中的xxxYyy属性,比如:字段user_name映射的是实体类中的userName属性。实现Mybatis的映射有四种方式,具体可以参考另一篇文章Mybatis数据库字段和实体属性的映射 -
创建Mybatis的实体类、mapper和service,用来查询数据库:

-
创建实体:
public class SysUser { private Long id; private String userName; private String password; private List<SysRole> sysRoleList; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public List<SysRole> getSysRoleList() { return sysRoleList; } public void setSysRoleList(List<SysRole> sysRoleList) { this.sysRoleList = sysRoleList; } }public class SysRole { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }public class SysUserRole { private Long id; private Long userId; private Long roleId; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } public Long getRoleId() { return roleId; } public void setRoleId(Long roleId) { this.roleId = roleId; } } - 创建
Mapper用来执行查询语句: -
因为为了省事使用了驼峰映射,所以不需要使用
xml文件来配置字段和实体的映射关系,直接使用注解编写sql即可。@Mapper @Repository public interface SysUserMapper { @Select("SELECT * FROM sys_user") List<SysUser> findAll(); @Select("SELECT * FROM sys_user WHERE user_name = #{userName}") SysUser findByUserName(@Param("userName") String userName); }@Mapper @Repository public interface SysRoleMapper { @Select("SELECT * FROM sys_role WHERE id = #{id}") SysRole findById(@Param("id") Long id); }@Mapper @Repository public interface SysUserRoleMapper { @Select("SELECT * FROM sys_user_role WHERE user_id = #{userId}") List<SysUserRole> findByUserId(@Param("userId") Long userId); } -
创建
service用来编写业务代码:@Service public class SysUserService { @Autowired private SysUserMapper sysUserMapper; public List<SysUser> findAll() { return sysUserMapper.findAll(); } public SysUser findByUserName(String userName) { return sysUserMapper.findByUserName(userName); } }@Service public class SysRoleService { @Autowired private SysRoleMapper sysRoleMapper; public SysRole findById(Long id) { return sysRoleMapper.findById(id); } }@Service public class SysUserRoleService { @Autowired private SysUserRoleMapper sysUserRoleMapper; public List<SysUserRole> findByUserId(Long userId) { return sysUserRoleMapper.findByUserId(userId); } } -
修改
WebSecurityConfig配置类,设置首页需要ADMIN角色才能访问:@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { //用于密码加密 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //将CustomUserService注册为bean @Bean public CustomUserService customUserService() { return new CustomUserService(); } //使用自定义的CustomUserService加载用户 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(this.customUserService()); super.configure(auth); } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/login")//设置登录页面 .loginProcessingUrl("/login")//自定义的登录接口 .failureUrl("/login?error")//登录失败的页面 .and() .authorizeRequests() .antMatchers("/login").permitAll()//设置不需要登陆就能访问登录页面 .antMatchers("/").hasAnyRole("ADMIN")//设置首页需要ADMIN角色才能访问 .anyRequest()//登录后可以访问所有页面 .authenticated() .and() .csrf().disable();//关闭csrf防护 } } - 修改
CustomUserService配置类,改为从数据库获取用户和角色: -
需要注意,数据库保存的密码必须是用
new BCryptPasswordEncoder().encode("密码")加密后的数据,否则不能登录。public class CustomUserService implements UserDetailsService { @Autowired private SysUserMapper userMapper; @Autowired private SysUserRoleMapper sysUserRoleMapper; @Autowired private SysRoleMapper sysRoleMapper; @Override public UserDetails loadUserByUsername(String username) { //通过用户名查询用户 SysUser user = userMapper.findByUserName(username); if (user == null) { throw new UsernameNotFoundException("用户名不存在"); } //查询用户的角色信息 List<SimpleGrantedAuthority> authorities = new ArrayList<>(); List<SysUserRole> sysUserRoleList = sysUserRoleMapper.findByUserId(user.getId()); for (SysUserRole sysUserRole : sysUserRoleList) { SysRole sysRole = sysRoleMapper.findById(sysUserRole.getRoleId()); if (sysRole != null) { authorities.add(new SimpleGrantedAuthority(sysRole.getName())); } } //返回查询到的用户,验证能否登录 return new User(user.getUserName(), user.getPassword(), authorities); } } - 重新启动项目,访问
localhost:8080,此时会跳转到自定义登录页面,输入刚才添加到数据库中的用户名和密码(密码是加密前的明文密码,例子中的用户名:user密码:123),点击登录,页面报错如下:

- 报错信息为403表示服务器拒绝访问,说明我们配置的角色起作用了。拒绝访问是因为数据库中的角色是
USER,而首页需要ADMIN角色才允许访问。 - 我们将数据库表
sys_role中的角色ROLE_USER改为ROLE_ADMIN,重新登录:

- 登录成功了:
