SpringBoot
springboot学习笔记
1、整合数据库
-
数据库连接的配置
spring: datasource: username: root password: root url: jdbc:mysql://localhost:3306/mybatis?useUnicode=ture&characterEncoding=utf-8&serverTimezone=UTC driver-class-name: com.mysql.jdbc.Driver -
整合druid
-
导入依赖
log4j log4j 1.2.17 com.alibaba druid 1.1.22 -
自定义数据源
#自定义数据源 type: com.alibaba.druid.pool.DruidDataSource #Spring Boot 默认是不注入这些属性值的,需要自己绑定 #druid 数据源专有配置 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入 #如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 -
配置druid连接池后台管理
@Configuration public class DruidConfig { @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource druidDataSource(){ return new DruidDataSource(); } //配置后台监控 @Bean public ServletRegistrationBean statViewServlet(){ ServletRegistrationBeanbean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*"); //存储后台设置参数的map集合 Map initParams = new HashMap<>(); initParams.put("loginUsername","admin"); //后台管理的账号 initParams.put("loginPassword","123456"); //后台管理的密码 //设置初始化参数 bean.setInitParameters(initParams); return bean; } }
-
-
整合mybatis
-
导入springboot整合mybatis的启动类依赖
org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.3 -
整合mybatis的yml配置
mybatis: mapper-locations: classpath:mapper/*.xml #配置映射mapper文件路径 # config-location: classpath:mybatis-config.xml #配置mybatis核心配置文件位置 不能和驼峰命名一起配置 configuration: map-underscore-to-camel-case: true #开启mybatis实体类属性驼峰命名 type-aliases-package: com.wt.springbootdata.model #指定实体类的包,起别名 -
mapper映射文件头配置信息
<?xml version="1.0" encoding="UTF-8" ?> -
dao层交给spring管理
-
方案一:在mapper接口文件上加@mapper和@Component注解
-
方案二:在mapper接口文件上加@mapper注解
? 在springboot启动类上加@MapperScan(basePackages = {"mapper接口所在的包"})
-
-
2、整合SpringSecurity
-
简介 :Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。也是SpringBoot底层安全模块的默认技术选型。
-
使用:
-
导入Security坐标依赖
org.springframework.boot spring-boot-starter-security -
编写Security配置类,继承WebSecurityConfigurerAdapter类,并加上@EnableWebSecurity注解
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { /** * 重写configure方法,进行权限授权 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { //添加不同的权限 http.authorizeRequests() //首页所有人都能访问 .antMatchers("/").permitAll() //等级1路径下,只有vip1用户才能访问 .antMatchers("/level1/**").hasRole("vip1") //等级1路径下,只有vip2用户才能访问 .antMatchers("/level2/**").hasRole("vip2") //等级1路径下,只有vip3用户才能访问 .antMatchers("/level3/**").hasRole("vip3"); //没有权限默认会跳转登录页面 http.formLogin(); //关闭csrf功能,正常注销 http.csrf().disable(); //开启注销功能,注销成功跳转首页 http.logout().logoutSuccessUrl("/"); } /** * 权限认证 * 密码要进行编译 new BCryptPasswordEncoder() * 用户信息默认应该从数据库中获取 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("test").password(new BCryptPasswordEncoder().encode("123")).roles("vip1","vip2") .and() .withUser("wt").password(new BCryptPasswordEncoder().encode("123")).roles("vip3"); } } -
前端页面结合thymeleaf模板,实现授权和认证:
1.导入thymeleaf模板依赖和thymeleaf和security整合的依赖
org.thymeleaf.extras thymeleaf-extras-springsecurity4 3.0.2.RELEASE org.springframework.boot spring-boot-starter-thymeleaf 2.补全约束
3.判断用户是否登录
sec:authorize="isAuthenticated()":判断用户是否登录,如果登录,则显示div的内容
sec:authentication="name":获取登录的用户名
sec:authentication="principal.authorities":获取当前登录用户,所具有的角色信息
4.根据当前用户所具有的角色,自动显示或隐藏内容
sec:authorize="hasRole('vip1')":如果当前用户,具有vip1角色信息,就显示该内容
5.自定义登录页面
loginPage("/toLogin"):跳转登录页面路径
loginProcessingUrl("/login"):登录表单的请求提交路径
usernameParameter("username"):页面用户名的参数名称,默认为username
passwordParameter("password"):页面密码的参数名称,默认为password
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login").usernameParameter("username").passwordParameter("password");6.记住登录角色功能
rememberMeParameter("remember"):记住我按钮的参数名称
记住密码//开启记住我功能 cookie默认保存两周 http.rememberMe().rememberMeParameter("remember");
-
3、shiro
3.1 Shiro快速入门
-
简介:Shiro是Apache旗下的一个Java安全权限管理框架。既可以作用在JavaSE环境,也可以在JavaEE环境中使用。Shiro可以完成认证,授权,加密,会话管理,Web集成,缓存等。
-
官网:http://shiro.apache.org/
-
快速入门
-
导入Maven依赖
org.apache.shiro shiro-core 1.4.1 org.slf4j jcl-over-slf4j 1.7.21 org.slf4j slf4j-log4j12 1.7.21 log4j log4j 1.2.17 -
创建log4j.properties
log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n # General Apache libraries log4j.logger.org.apache=WARN # Spring log4j.logger.org.springframework=WARN # Default Shiro logging log4j.logger.org.apache.shiro=INFO # Disable verbose logging log4j.logger.org.apache.shiro.util.ThreadContext=WARN log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN -
创建shiro.ini
[users] # user 'root' with password 'secret' and the 'admin' role root = secret, admin # user 'guest' with the password 'guest' and the 'guest' role guest = guest, guest # user 'presidentskroob' with password '12345' ("That's the same combination on # my luggage!!!" ;)), and role 'president' presidentskroob = 12345, president # user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz' darkhelmet = ludicrousspeed, darklord, schwartz # user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz' lonestarr = vespa, goodguy, schwartz # ----------------------------------------------------------------------------- # Roles with assigned permissions # # Each line conforms to the format defined in the # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc # ----------------------------------------------------------------------------- [roles] # 'admin' role has all permissions, indicated by the wildcard '*' admin = * # The 'schwartz' role can do anything (*) with any lightsaber: schwartz = lightsaber:* # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with # license plate 'eagle5' (instance specific id) goodguy = winnebago:drive:eagle5 -
新建Quickstart文件
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Quickstart { private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class); public static void main(String[] args) { Factoryfactory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); // 获取当前的用户对象Subject Subject currentUser = SecurityUtils.getSubject(); // 获取当前用户的Session对象 存值取值 Session session = currentUser.getSession(); session.setAttribute("someKey", "aValue"); String value = (String) session.getAttribute("someKey"); if (value.equals("aValue")) { log.info("Retrieved the correct value! [" + value + "]"); } // 判断当前用户是否被认证 if (!currentUser.isAuthenticated()) { //通过用户名和密码生成token 令牌。 UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); //设置记住我 token.setRememberMe(true); try { //执行登录操作 currentUser.login(token); } catch (UnknownAccountException uae) { //用户名错误异常 log.info("There is no user with username of " + token.getPrincipal()); } catch (IncorrectCredentialsException ice) { //密码错误异常 log.info("Password for account " + token.getPrincipal() + " was incorrect!"); } catch (LockedAccountException lae) { //账户被锁定异常 log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } // ... catch more exceptions here (maybe custom ones specific to your application? catch (AuthenticationException ae) { //认证异常 //unexpected condition? error? } } //say who they are: //print their identifying principal (in this case, a username): log.info("User [" + currentUser.getPrincipal() + "] logged in successfully."); //test a role: //判断角色信息 if (currentUser.hasRole("schwartz")) { log.info("May the Schwartz be with you!"); } else { log.info("Hello, mere mortal."); } //test a typed permission (not instance-level) //判断权限信息 if (currentUser.isPermitted("lightsaber:wield")) { log.info("You may use a lightsaber ring. Use it wisely."); } else { log.info("Sorry, lightsaber rings are for schwartz masters only."); } //a (very powerful) Instance Level permission: if (currentUser.isPermitted("winnebago:drive:eagle5")) { log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " + "Here are the keys - have fun!"); } else { log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!"); } //注销 currentUser.logout(); //关闭系统 System.exit(0); } }
-
3.2 SpringBoot整合Shiro
-
shiro三大对象
- Subject:当前操作用户。
- SecurityManager:Shiro框架的核心,并通过它进行安全管理。
- Realm:Shiro与应用安全数据间的“桥梁”或者“连接器”。
-
环境搭建
-
导入shiro相关的依赖
com.github.theborakompanioni thymeleaf-extras-shiro 2.0.0 org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.3 mysql mysql-connector-java runtime org.springframework.boot spring-boot-starter-jdbc com.alibaba druid 1.1.22 org.apache.shiro shiro-spring 1.6.0 org.springframework.boot spring-boot-starter-thymeleaf -
编写自定义的认证授权配置类:UserRealm
package com.wt.shirospringboot.config; import com.wt.shirospringboot.model.User; import com.wt.shirospringboot.service.serviceImpl.UserServiceImpl; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;import javax.annotation.Resource;
/**
-
自定义UserRealm
*/
public class UserRealm extends AuthorizingRealm {@Resource
private UserServiceImpl userService;/**
-
授权
-
@param principalCollection
-
@return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获取当前用户对象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();//授权,将数据库中存储的用户权限,并进行授权
info.addStringPermission(currentUser.getPerms());
return info;
}
/**
-
认证
-
@param authenticationToken
-
@return
-
@throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//连接数据库,获取用户信息
User user = userService.queryUserByName(token.getUsername());if (user == null){
//返回null之后,自动抛出UnknownAccountException异常
return null;
}//将用户信息存储到Session中
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("user",user);//密码。shiro自动认证,密码做了加密
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
}
-
- 编写Shiro配置文件ShiroConfig ```Java package com.wt.shirospringboot.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 factoryBean.setSecurityManager(securityManager); //添加shiro的内置过滤器 /* anon:无需认证就可以访问 authc:必须认证了才可以访问资源 user:必须选择了记住我功能才能访问 perms:必须对某个资源有权限才能访问 role:拥有某个角色的权限才能访问 */ MapfilterMap = new LinkedHashMap<>(); //授权 /user/add路径下必须有user:add权限才能访问,写在authc权限设置后,不生效 filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/update","perms[user:update]"); //设置user/下的所有路径,都必须认证了才能访问 filterMap.put("/user/*","authc"); factoryBean.setFilterChainDefinitionMap(filterMap); //设置登录页面 factoryBean.setLoginUrl("/toLogin"); //设置没有权限跳转的页面 factoryBean.setUnauthorizedUrl("/unauthorized"); return factoryBean; } /** * 创建shiro安全管理类 * @param userRealm * @return */ @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联UserRealm securityManager.setRealm(userRealm); return securityManager; } /** * 创建realm对象 * @return */ @Bean public UserRealm userRealm(){ return new UserRealm(); } /** * 用来整合Shiro和thymeleaf * @return */ @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } } -
登录之后,进行权限判断
@RequestMapping("/login") public String login(String username,String password,Model model){ //获取当前用户 Subject subject = SecurityUtils.getSubject(); //封装登录数据 UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { //执行登录方法,不报异常就是通过认证 subject.login(token); return "index"; }catch (UnknownAccountException e){ model.addAttribute("msg","用户名错误"); return "login"; }catch (IncorrectCredentialsException e){ model.addAttribute("msg","密码错误"); return "login"; } } -
前端页面shiro与thymeleaf整合
Title 首页
-
4、集成Swagger
4.1 简介
- 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
- 总体目标是使客户端和文件系统作为服务器以同样的速度来更新。
4.2 SpringBoot集成swagger
-
导入swagger依赖 swagger2+swagger-ui
io.springfox springfox-swagger2 2.9.2 io.springfox springfox-swagger-ui 2.9.2 -
编写swagger配置类
package com.wt.swagger.config; import org.springframework.context.annotation.Configuration; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { } -
swagger接口测试页面地址:http://localhost:8080/swagger-ui.html
4.3 配置swagger
-
通过注册Docket实例,对swagger进行配置。 通过配置多个Docket进行多个分组设置
-
方法:
-
.apiInfo() //swagger页面信息配置 -
//组合使用 .select() .apis(RequestHandlerSelectors.basePackage("com.wt.swagger.controller")) //指定swagger要扫描的接口 .paths(PathSelectors.ant("/wt/**")) //指定swagger不扫描的接口 .build()扫描可传入的参数:
- basePackage():指定要扫描的包路径
- any():扫描全部
- none():全部都不扫描
- withClassAnnotation():扫描类上有指定注解的接口方法 参数:类的注解class对象 RestController.class
- withMethodAnnotation():扫描方法上有指定注解的接口方法 参数:方法的注解的class对象 RequestMapping.class
-
enable(false) //是否在项目中禁用swagger,默认为true -
groupName("wt的分组") //配置默认分组信息
-
-
获取当前的项目环境
配置文件:
- application.properties:主配置文件
- application-dev.properties :生产环境配置文件
- application-test.properties :测试环境配置文件
在主配置文件中进行指定当前环境
-
spring.profiles.active=dev //指定为生产环境
获取当前环境
//设置要显示swagger环境 Profiles profiles = Profiles.of("dev", "test"); //判断当前环境是否是在设置的环境中 boolean flag = environment.acceptsProfiles(profiles); -
SwaggerConfig配置类
package com.wt.swagger.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.core.env.Profiles; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; @Configuration @EnableSwagger2 public class SwaggerConfig { /** * 配置Swagger的Docket的bean实例 * @return */ @Bean public Docket docket(Environment environment){ ApiInfo apiInfo = apiInfo(); //设置要显示swagger环境 Profiles profiles = Profiles.of("dev", "test"); //判断当前环境是否是在设置的环境中 boolean flag = environment.acceptsProfiles(profiles); return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .groupName("wt的分组") .enable(flag) .select() .apis(RequestHandlerSelectors.basePackage("com.wt.swagger.controller")) .paths(PathSelectors.ant("/wt/**")) .build(); } /** * 配置swagger页面信息 * @return */ private ApiInfo apiInfo(){ //作者信息 Contact contact = new Contact("吴涛", "", "2456512878@qq.com"); return new ApiInfo( "吴涛的swagger接口文档", "springboot集成swagger项目的demo接口测试文档", "v1.0", "urn:tos", contact, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList<>()); } }
4.2 swagger常用注解
- @Api()用于类;
表示标识这个类是swagger的资源 - @ApiOperation()用于方法;
表示一个http请求的操作 - @ApiParam()用于方法,参数,字段说明;
表示对参数的添加元数据(说明或是否必填等) - @ApiModel()用于类
表示对类进行说明,用于参数用实体类接收 - @ApiModelProperty()用于方法,字段
表示对model属性的说明或者数据操作更改 - @ApiIgnore()用于类,方法,方法参数
表示这个方法或者类被忽略 - @ApiImplicitParam() 用于方法
表示单独的请求参数 - @ApiImplicitParams() 用于方法,包含多个 @ApiImplicitParam
5、任务
5.1 异步任务
-
@Async 标明该方法为异步方法,在运行时,使用异步处理
-
@EnableAsync 写在springboot启动类上,开启异步注解功能
-
例:用户访问/hello接口时,会执行 asyncService.hello();方法时,会同时异步响应消息
@Async public void hello(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("程序正在执行"); }@RequestMapping("/hello") public String hello(){ asyncService.hello(); return "响应消息来了"; }
5.2 邮件任务
-
导入邮件依赖
org.springframework.boot spring-boot-starter-mail -
邮件信息配置
# 邮箱地址 spring.mail.username=2456512878@qq.com # 邮箱生成的验证码 spring.mail.password=nqeocllkxzibeaje # qq邮箱主机地址 spring.mail.host=smtp.qq.com # 开启加密验证 spring.mail.properties.mail.stml.ssl.enable=true -
编写代码
@Resource JavaMailSenderImpl mailSender; @Test void contextLoads() { //发送一封简单的邮件 SimpleMailMessage message = new SimpleMailMessage(); message.setSubject("邮件发送测试"); message.setText("这是一封通过Java发送的邮件"); message.setTo("2456512878@qq.com"); message.setFrom("2456512878@qq.com"); mailSender.send(message); } @Test void contextLoads2() throws MessagingException { //发送一封复杂的邮件 MimeMessage message = mailSender.createMimeMessage(); //组装 参数:message-邮件对象,true-开启多文件上传 MimeMessageHelper helper = new MimeMessageHelper(message, true); //正文 helper.setSubject("发送复杂邮件测试"); //参数true:开启html解析 helper.setText("您的验证码是:33355
",true); //附件 helper.addAttachment("壁纸.jpg",new File("C:\\Users\\Administrator\\Pictures\\t01a22ce414beb453d4.jpg")); //设置发送双方 helper.setTo("2456512878@qq.com"); helper.setFrom("2456512878@qq.com"); mailSender.send(message); }
5.3 定时任务
-
在springboot启动类上添加@EnableScheduling注解,开启定时任务注解。
-
@Scheduled:标注需要定时的任务方法(定时任务方法所在的类,需要加上@Component注解,该类也需要在启动类的子包下)
/** * 定时执行的任务 * cron:表达式,指定该任务什么时候执行 在约定的时间执行已经计划好的工作 */ @Scheduled(cron = "30 56 8 * * ?") public void hello(){ System.out.println(new Date() + "定时任务运行了!!!!"); }