*********
*********
在前不久用了spring boot、mybatis、spring security搭建了一个工程,中间经历了各种坑,最后得到一条经验:spring的文档很详细,入门最好以官方文档为准。
这里讲的是以mav作为依赖管理工具
搭建spring boot应用快捷的方式是在pom.xml中引入spring-boot-starter-parent 作为parent,如下:
4.0.0
com.tw
twboot
war
0.0.1-SNAPSHOT
twboot Maven Webapp
http://maven.apache.org
1.2.0
org.springframework.boot
spring-boot-starter-parent
1.5.9.RELEASE
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-security
org.thymeleaf.extras
thymeleaf-extras-springsecurity4
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis-spring-boot}
junit
junit
commons-fileupload
commons-fileupload
1.3.1
commons-io
commons-io
2.4
javax.servlet
servlet-api
2.5
twboot
spring boot 中默认会获取classpath下的application.yml或者application.propertis文件作为配置文件
我用的前者
server:
port: 80
spring:
datasource:
username: xyz
password: xyz
driver-class-name: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@127.0.0.1:1521:XE
dbcp2:
max-idle: 10
validation-query: select 1 from dual
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
mybatis:
type-aliases-package: com.tw.entity
mapper-locations:
- classpath:mapping/*.xml
上面的server.port 表示spring boot内置tomcat启动的端口是80,view层显示用的thymeleaf模板,模板前后缀也在配置文件中定义,这个和spring mvc那种配置类似;
另工程中只用用一种view表示方式,用了thymeleaf就不要用jsp了,网上说的两种模板解析链是有先后处理顺序的,也就是说是有优先级;
在我们的package最顶层新建一个继承SpringBootServletInitializer的类(内容如下),这样一个spring boot项目就搭建好了
package com.tw;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
@MapperScan("com.tw.dao")
public class StartApp extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(StartApp.class);
}
//添加Tomcat支持
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(StartApp.class);
}
}
上面的
@SpringBootApplication 表面这是一个springboot应用,
@MapperScan("com.tw.dao") 这个表示mybatis自动扫描dao接口的包名,
这个包下的接口会自动和spring boot配置项mapper-locations中的mybatis sql配置文件映射
在spring boot中controller分为两类,一种是返回数据的Controller,一种是返回视图的Controller,分别注解是
@RestController
@Controller
我这里写一个简单的controller
package com.tw.controller;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import javax.servlet.ServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CommonController {
@PreAuthorize("hasRole('RRR')")
@RequestMapping(value={"/","/home"})
public String index() {
return "home/home";
}
@RequestMapping("/login")
public String login(Model model) {
System.out.println("to login----");
return "login/login";
}
@RequestMapping("/thymeleaf")
public String test(Map map,ServletResponse response) throws UnsupportedEncodingException, IOException{
map.put("name", "test");
System.out.println("thymeleaf----");
return "thymeleaf/hello2";
}
/**
* 功能描述:角色管理
* CHENY037 2017年11月29日
* @return
*/
@RequestMapping("/roleManage")
@PreAuthorize("hasRole('ROLE_MANAGE')")
public String roleManage(){
return "home/role";
}
}
自定义登录界面和自定义用户名密码校验
配置类:
package com.tw.config.Security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* 配置类:
* 配置security的登录页面和传递的参数,公共路径权限属性等
*
* @author CHENY037
*
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UrlUserService urlUserService;
@Autowired
SessionRegistry sessionRegistry;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
// .antMatchers("/logout").permitAll()
.antMatchers("/img/**").permitAll()
.antMatchers("/js/**").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/bootstrap/**").permitAll()
.antMatchers("/fonts/**").permitAll()
.antMatchers("/favicon.ico").permitAll()
.anyRequest().authenticated()
//登录相关
.and().formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password").defaultSuccessUrl("/home")
.and().sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry)
.and().and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.and()
.httpBasic();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//这里是新增一个默认用户
auth.inMemoryAuthentication().withUser("huahua").password("hello").roles("ADMIN");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(urlUserService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return (String)rawPassword;//MD5Util.encode((String) rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
System.out.println(encodedPassword + "---" + (String)rawPassword);
return encodedPassword.equals((String) rawPassword);
}
});
}
@Bean
public SessionRegistry getSessionRegistry(){
SessionRegistry sessionRegistry = new SessionRegistryImpl();
return sessionRegistry;
}
}
自定义用户名密码校验类
package com.tw.config.Security;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.tw.dao.RoleDao;
import com.tw.dao.UserDao;
import com.tw.entity.role.TwRole;
import com.tw.entity.role.TwUser;
/**
* 自定义用户名密码校验实现
*
* @author CHANY037 2017-11
*
*/
@Service
public class UrlUserService implements UserDetailsService {
@Autowired
UserDao userDao;
@Autowired
RoleDao roleDao;
/**
* employeeId 用户工号,在数据库中保证存储唯一
*/
@Override
public UserDetails loadUserByUsername(String employeeId) { //重写loadUserByUsername 方法获得 userdetails 类型用户
TwUser user = userDao.findByEmployeeId(employeeId);
if(user == null){
throw new UsernameNotFoundException(employeeId + " do not exist!");
} else {
System.out.println(user.getPassword() + " --pw-- ");
List roles = roleDao.findRoleByEmployeeId(employeeId);
List grantedAuthorities = new ArrayList();
//写入用户的角色 *** 切记 由于框架原因 角色名称要以 ROLE_ 开头 **** 血泪史 ****
//源码:org.springframework.security.access.expression.SecurityExpressionRoot hasAnyRole()
for (TwRole role : roles) {
if (role != null && role.getRoleName() != null) {
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleCode());
grantedAuthorities.add(grantedAuthority);
}
}
org.springframework.security.core.userdetails.User uu = new User(employeeId, user.getPassword(), grantedAuthorities);
return uu;
}
}
}
登录界面html 即 上面
CommonController 里定义的login方法返回的视图
Login