SpringBoot
了解SpringBoot:https://blog.csdn.net/Delia_theme/article/details/88681722
学习文档:http://c.biancheng.net/spring_boot/example.html ---狂神笔记
springboot狂神笔记:https://blog.csdn.net/qq_43167873/article/details/122471275
Spring Boot是在Spring的基础上面搭设的框架,目的是为了简化Spring项目的搭设和开发过程
SpringBoot四个主要特性
1、SpringBoot Starter:他将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Maven或Gradle构建中;
2、自动配置:SpringBoot的自动配置特性利用了Spring4对条件化配置的支持,合理地推测应用所需的bean并自动化配置他们;
3、命令行接口:(Command-line-interface, CLI):SpringBoot的CLI发挥了Groovy编程语言的优势,并结合自动配置进一步简化Spring应用的开发;
4、Actuatir:它为SpringBoot应用的所有特性构建一个小型的应用程序。
Spring Boot的核心功能
1、 可独立运行的Spring项目:Spring Boot可以以jar包的形式独立运行。
2、 内嵌的Servlet容器:Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow,无须以war包形式部署项目。
3、 简化的Maven配置:Spring提供推荐的基础 POM 文件来简化Maven 配置。
4、 自动配置Spring:Spring Boot会根据项目依赖来自动配置Spring 框架,极大地减少项目要使用的配置。
5、 提供生产就绪型功能:提供可以直接在生产环境中使用的功能,如性能指标、应用信息和应用健康检查。
6、 无代码生成和xml配置:Spring Boot不生成代码。完全不需要任何xml配置即可实现Spring的所有配置。
SpringBoot注解:
1、@controller: controller控制器层(注入服务) 2、@service : service服务层(注入dao) 3、@repository : dao持久层(实现dao访问) 4、@component: 标注一个类为Spring容器的Bean,(把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
idea创建springboot项目
1.新建项目选择“Spring Initializr”
2.选择“Maven Project”
3.选择“web”--->“Spring web”(可以不选)
4.修改项目名--->"Finish"
5.删除没必要文件
6.项目建成后可能遇到的问题
@SpringBootApplication报错
解决:https://blog.csdn.net/duduhh/article/details/109864569
自动配置原理
SpringBoot所有的自动配置,都在启动类中被扫描并加载:所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的starter们就有对应的启动器了,有了启动器,我们的自动装配就会生效,然后就配置成功了
1.SpringBoot在启动的时候,从类路径下/META-INF/spring.factories获取指定的值
2.将这些自动配置的类导入容器,自动配置类就会生效,帮我们进行自动配置
3.以前我们需要自动配置的东西,现在不需要了
4.整合javaEE,解决方案和自动配置的东西都在Spring-boot-autoconfigure下
5。它会把所有需要导入的组件,以类名的方式返回这些组件,这些组件就会被添加到容器
6.容器中也会存在非常多的XXXAutoConfigure的文件(@Bean),就是这个类给容器导入了这个场景所需要的所有组件并自动配置
SpringApplication作用
1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类
run方法流程分析
yaml基础语法:
YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)
特别注意:yaml文件“ : ”后一定要有个空格
# k-v键值对 name: xiaoqi #相当于name=xiaoqi # 存对象 student: name: xiaoqi age: 12 # 行内写法 student1: {name: xiaoqi,age: 13} #数组 pets: - cat - dog - pyg pets1: [cat,dog]
可能遇到的问题:springBoot读取*.properties文件中文乱码的问题
解决:https://blog.csdn.net/javahighness/article/details/92674878
JSR303数据效验
学习文档:https://www.jianshu.com/p/554533f88370
@Validated //JSR303数据效验
@Email(message = "邮箱格式错误") //限定name为email格式数据
可能遇到的问题:@Eamil()等注解爆红
解决:再pom.xml中加入
<!--解决JSR303效验爆红--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
或者导入以下包后,删除原来注解,重新注解(点击提示注解)----注解会有删除线
<!--jie解决JSR303效验爆红--> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.17.Final</version> <scope>compile</scope> </dependency>
自定义图标
favicon.ioc图片放入static文件中,需在properties中插入:
#关闭默认图标 #spring.mvc.favicon.enabled=false spring.favicon.enabled = false
Thymeleaf模板引擎
Thymeleaf 官网:https://www.thymeleaf.org/
导入依赖:
<dependency> <!--都是基于3.xx开发的--> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency>
<!--静态资源加载优先级:resources>static(默认)>puiblic-->
-
简单表达式:
- 变量表达式:
${...}
- 选择变量表达式:
*{...}
- 消息表达式:
#{...}
- 链接网址表达式:
@{...}
- 片段表达式:
~{...}
- 变量表达式:
可能遇到的问题: th爆红或者msg爆红
th爆红:修改html标签
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
msg爆红:在该代码的上一行添加一句注释
<!--@thymesVar id="msg" type="String"--> //注释即可 <h1 th:text="${msg}"></h1>
Thymeleaf中对CSS引用失效问题:
注释掉 @EnableWebMvc
@EnableWebMvc作用: 1. 使用@EnableWebMvc注解启用spring mvc的基于java config的配置 2. 实现WebMvcConfigurer接口的方法可以自定义spring mvc的配置 3. 对于第2个意思,建议采用继承WebMvcConfigurerAdapter类来实现 4. 如果想要让继承WebMvcConfigurerAdapter的自定义配置的子类起作用,那这个类应该是配置类(比如加上注解@Configuration,毕竟这个类应该托管到spring 容器内,spring mvc才会知道这个子类,要不这些自定义配置怎么起作用)
页面国际化
1.配置i18n文件
2.在项目中进行按钮自动切换
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a> <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
3.自定义一个组件LocaleResolver
package com.xinyu.config; import org.springframework.web.servlet.LocaleResolver; import org.thymeleaf.util.StringUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Locale; //国际化 public class MyLocaleResolver implements LocaleResolver { //解析请求 @Override public Locale resolveLocale(HttpServletRequest request){ String language = request.getParameter("l"); System.out.println("language===>"+language); Locale locale = Locale.getDefault(); //如果没有就是要默认的 //如果请求的的链接携带了国际化参数 if(!StringUtils.isEmpty(language)){ //zh_CN String[] splits = language.split("_"); //国家,地区 locale = new Locale(splits[0],splits[1]); } return locale; } @Override public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { } }
4.在config核心文件中将组件写入spring容器@Bean
//使用自定义国际化组件 @Bean //将组件放入bean中(ioc容器) public LocaleResolver localeResolver(){ return new MyLocaleResolver(); }
拦截器
通过拦截session实现对用户拦截
package com.xinyu.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thymeleaf.util.StringUtils; import javax.servlet.http.HttpSession; @Controller public class LoginController { //@ResponseBody //将java对象转为json格式的数据,将controller的方法返回的对象转换为指定的格式写入到response对象的body区 @RequestMapping("/user/login") public String login( @RequestParam("username") String username, @RequestParam("password") String password, Model model, HttpSession session){ //具体业务 if(!StringUtils.isEmpty(username) && "123456".equals(password)){ session.setAttribute("loginUser",username); //通过session往后台传递值 return "redirect:/main.html"; }else { //登陆失败 // model.addAttribute(K,V)往前台传数据,可以传对象,可以传List,通过el表达式 ${}可以获取到,类似于request.setAttribute(“sts”,sts)效果一样 model.addAttribute("msg","用户名或密码错误"); return "index.html"; } } }
1.编写拦截器
package com.xinyu.config; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //登录拦截器 public class LoginHandlerInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{ //登录成功后应该有用户的session Object loginUser = request.getSession().getAttribute("loginUser"); //先获取session,然后从session中获取传递的值 if(loginUser==null){ request.setAttribute("msg","没有权限,请先登录"); request.getRequestDispatcher("index").forward(request,response); return false; }else { return true; } } }
2.在在config核心文件使用
//配置登录拦截器 @Override public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(new LoginHandlerInterceptor()) .addPathPatterns("/**") //拦截界面 .excludePathPatterns("/index","/","/user/login","/css/**","/js/**","/img/**"); //不拦截的界面 }
前端提取公共模块
1.设置模块
<div th:fragment="topbar"> ... </div>
2.引用
1.替换:<div th:replace="~{commons/commons::topbar}"></div>
2.插入:<div th:insert="~{commons/commons::topbar}"></div>
3.传值与接收(引用向被引用传参)
引用传参:<div th:replace="~{commons/commons::sidebar(active='main.html')}"></div> //传递参数active,值为main.html
被引用接收参数并使用: th:class="${active=='main.html' ? 'nav-link active':'nav-link'}" //
整合JDBC
新建项目,选择SQL,勾选'JDBC API'和'MySQL Driver'
新建application.yaml,链接数据库时,将url替换成下面的url
spring: datasource: username: jdbc_root password: 123456 url: jdbc:mysql://localhost:3307/mybaties?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC driver-class-name: com.mysql.jdbc.Driver
Druid:DruidDataSource的使用、配置
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version> <!--1.1.23可能会报错-->
</dependency>
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: commons-log.connection-logger-name: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
导入log4j
<!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
添加 DruidDataSource 组件到容器中,并绑定属性(新建config-->DruidConfig)
package com.xinyu.config; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.support.http.StatViewServlet; import com.alibaba.druid.support.http.WebStatFilter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; import java.io.File; import java.util.HashMap; /* 1.表明当前类是一个配置类,是方法bean的源 2.将@Configuration配置的AppConfig的beanDefinitioin属性赋值为full类型的,保证AppConfig类型 可以转变为cglib类型 3.将@Configuration配置的AppConfig由普通类型转变为cglib代理类型,后会生成cglib代理对象,通 过代理对象的方法拦截器, 可以解决AppConfig内部方法bean之间发生依赖调用的时候从容器中去获取,避免了多例的出现 * */ @Configuration public class DruidConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") //绑定到application.xml文件中 生效 public DataSource druidDateSource(){ return new DruidDataSource(); } //因为SpringBoot内置了servlet容器,所有没有web.xml,替代方法、:ServletRegistrationBean //后台监控功能 @Bean public ServletRegistrationBean statViewServlet(){ ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");//访问这个就可以进入后台监控页面,写死的 //后台需要有人登录 //账号密码配置也是死的 HashMap<String,String> initParameters = new HashMap<>(); //增加配置 initParameters.put("loginUsername","admin"); initParameters.put("loginPassword","123456");//key是固定的 //允许谁能访问 initParameters.put("allow",""); bean.setInitParameters(initParameters);//设置初始化参数 return bean; } //filter后台过滤 @Bean public FilterRegistrationBean webServletFilter(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new WebStatFilter()); //可以过滤哪些请求 HashMap<String,String> map = new HashMap<>(); map.put("exclusions","*.js,*.css,/druid/*");//这些东西不进行统计 bean.setInitParameters(map); return bean; } }
测试:浏览器访问:http://localhost:8080/druid
整合MyBatis
总结:
1.导入包
<!--1.导入mybatis--> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency>
<!--2.数据库驱动-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--2.导入lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
lombok注解:https://www.cnblogs.com/aspirant/p/10298752.html
2.配置文件
#端口号
server.port=8080
#关闭默认图标
#spring.mvc.favicon.enabled=false
spring.favicon.enabled = false
#关闭模板引擎的缓存
spring.thymeleaf.cache = false
#设置url首页名
#server.servlet.context-path = /xinyu
#国际化配置文件真实位置
spring.messages.basename = i18n.login
#时间日期格式
spring.mvc.format.date = yyyy-MM-dd
spring.datasource.username=jdbc_root spring.datasource.password=123456 spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?userUnicode=true&useSSL=true&characterEncoding=utf8 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#整合Mybatis
#让spring识别到mapper文件
mybatis.type-aliases-package=com.xinyu.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
3.mybatis配置
4.编写sql
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xinyu.mapper.UserMapper"> <select id="queryUserList" resultType="User"> select * from user </select> <select id="queryUserById" parameterType="int" resultType="User"> select * from user where id = #{id} </select> <update id="updateUser" parameterType="User" > update user set name=#{name},pwd=#{pwd} where id = #{id} </update> <insert id="addUser" parameterType="User"> insert into user(id,name,pwd) values (#{id},#{name},#{pwd}) </insert> <delete id="deleteUser" parameterType="int"> delete from user where id = #{id} </delete> </mapper>
5.service层调用dao(mapper)层
6.controller层调用service层
SpringSecurity
SpringSecurity是Springboot底层安全模块默认的技术选型,可以实现强大的Web安全机制,只需少数的spring-boot--spring-security
依赖,进行少量的配置,就可以实现
记住几个类 :
WebSecurityConfigurerAdapter:自定义Security策略
AuthenticationManagerBuilder:自定义认证策略
@EnableWebSecurity:开启WebSecurity模式
两个单词:en是认证,or是权限
认证方式:Authentication
权限:Authorization
导入依赖
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> </dependency>
认证,授权,注销
package com.xinyu.config; 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.crypto.bcrypt.BCryptPasswordEncoder; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { //链式编程 @Override protected void configure(HttpSecurity http) throws Exception { //首页所有人可以访问,功能页对应有权限人访问 //请求授权规则 http.authorizeRequests() .antMatchers("/").permitAll() .antMatchers("/level1/**").hasRole("vip1") .antMatchers("/level2/**").hasRole("vip2") .antMatchers("/level3/**").hasRole("vip3"); //没有权限返回登陆页面 http.formLogin().loginPage("/toLogin").usernameParameter("user").usernameParameter("pwd").loginProcessingUrl("/toLogin"); //防止网站工具:get post http.csrf().disable(); //关闭scrf功能 //注销 //http.logout().logoutUrl("/"); //注销退转url http.logout().logoutSuccessUrl("/toLogin"); //注销成功退转url // 开启记住我功能:本质就是记住一个cookies,默认保存2周 //http.rememberMe().rememberMeParameter("remember"); http.rememberMe(); } //认证 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception{ auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("xinyu").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3") .and() .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3"); } //new BCryptPasswordEncoder().encode("123456") 加密 }
index.html开启权限
1.引入依赖
xmlns:sec=“http://www.thymeleaf.org/thymeleaf-extras-springsecurity5”
2.编写
<div sec:authorize="!isAuthenticated()"> 未登录显示 <div sec:authorize="isAuthenticated()"> 以登陆显示
用户名:<span sec:authentication="name"></span>
角色:<span sec:authentication="principal.authorities"></span>
整合Shiro
Apache Shiro™ 是一个功能强大且易于使用的 Java 安全框架,可执行身份验证、授权、加密和会话管理。
核心三大对象:用户Subject, 管理用户SecurityManager, 连接数据Realms
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
1.导入Shiro的依赖
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version> </dependency> <!--configure logging--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.30</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
2.1.log4j.peoperties
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
2.2.shiro.ini (idea需要安装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
3.启动类 Quickstart (java文件下)
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ 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; /** * Simple Quickstart application showing how to use Shiro's API. * 简单入门Shiro使用API * * @since 0.9 RC2 */ public class Quickstart { private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class); public static void main(String[] args) { // The easiest way to create a Shiro SecurityManager with configured // realms, users, roles and permissions is to use the simple INI config. // We'll do that by using a factory that can ingest a .ini file and // return a SecurityManager instance: // Use the shiro.ini file at the root of the classpath // (file: and url: prefixes load from files and urls respectively): // 读取配置文件: Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); // for this simple example quickstart, make the SecurityManager // accessible as a JVM singleton. Most applications wouldn't do this // and instead rely on their container configuration or web.xml for // webapps. That is outside the scope of this simple quickstart, so // we'll just do the bare minimum so you can continue to get a feel // for things. SecurityUtils.setSecurityManager(securityManager); // Now that a simple Shiro environment is set up, let's see what you can do: // get the currently executing user: // 获取当前的用户对象 Subject Subject currentUser = SecurityUtils.getSubject(); // Do some stuff with a Session (no need for a web or EJB container!!!) //通过当前用户拿到Shiro的Session 可以脱离web存值取值 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 + "]"); } // let's login the current user so we can check against roles and permissions: //判断当前的用户是否被认证 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!"); } //all done - log out! //注销 currentUser.logout(); //结束 System.exit(0); } }
方法总结
// 获取当前的用户对象 Subject Subject currentUser = SecurityUtils.getSubject(); //获得subject Session session = currentUser.getSession(); //通过subject拿到session currentUser.isAuthenticated() //判断当前用户是否被认证 currentUser.getPrincipal() //获取当前用户认证 currentUser.hasRole("schwartz") //获取当前用户所拥有的角色 currentUser.isPermitted("lightsaber:wield") //获取当前用户的权限 currentUser.logout(); //注销
学习文档:https://blog.csdn.net/weixin_44635198/article/details/107701061
SpringBoot整合Shiro环境搭建
1.导入依赖
<!-- Subject 用户 SecurityManager 管理所有用户 Realm 连接数据库 --> <!--shiro整合spring的包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.3</version> </dependency> <dependency> <!--都是基于3.xx开发的--> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency>
2.config自定义类UserRealm
public class UserRealm extends AuthorizingRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=>授权doGetAuthorizationInfo"); return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了=>认证doGetAuthenticationInfo"); //从数据库中获取用户名与密码 String name = "root"; String password = "123456"; UsernamePasswordToken userToken = (UsernamePasswordToken)token; if(!userToken.getUsername().equals(name)){ return null; } //密码认证,shiro做 return new SimpleAuthenticationInfo("",password,""); } }
3.config---ShiroConfig
@Configuration public class ShiroConfig { //ShiroFilterFactoryBean---3 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); //添加shiro的内置过滤器 /* * anon: 无需认证就可访问 * authc: 必须认证才能访问 * user: 必须拥有 记住我 功能才能有 * perms: 拥有对某个资源权限才能访问 * role: 拥有某个角色权限才能访问 * */ Map<String,String> filterMap = new LinkedHashMap<>(); // filterMap.put("/user/add","authc"); // filterMap.put("/user/update","authc"); filterMap.put("/user/*","authc"); bean.setFilterChainDefinitionMap(filterMap); //设置登陆界面 bean.setLoginUrl("/toLogin"); return bean; } //@Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常 //@Qualifier限定描述符除了能根据名字进行注入,更能进行更细粒度的控制如何选择候选者 //DafaultWebSecurityManager---2 @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 关联userRealm securityManager.setRealm(userRealm); return securityManager; } //创建reaml对象,需要自定义类---1 @Bean(name = "userRealm") public UserRealm userRealm(){ return new UserRealm(); } }
4.controller
@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); //执行登录的方法,没有异常说明ok return "index"; }catch (UnknownAccountException e){ model.addAttribute("msg","用户名错误"); return "login"; }catch (IncorrectCredentialsException e){ model.addAttribute("msg","密码错误"); return "login"; } }
shiro整合Mybatis
1.导入依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>nuc.ss</groupId> <artifactId>shiro-springboot</artifactId> <version>0.0.1-SNAPSHOT</version> <name>shiro-springboot</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.3.0.RELEASE</spring-boot.version> </properties> <dependencies> <!-- Subject 用户 SecurityManager 管理所有用户 Realm 连接数据库 --> <!--shiro-thymeleaf整合--> <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency> <!--引入mybatis,这是MyBatis官方提供的适配spring Boot的,而不是spring Boot自己的--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <!--shiro整合spring的包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.3</version> </dependency> <!--thymeleaf--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2.1.配置文件application.yml的编写
spring: datasource: username: root password: 123456 #?serverTimezone=UTC解决时区的报错 url: jdbc:mysql://localhost:3307/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver 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 mybatis: type-aliases-package: nuc.ss.pojo mapper-locations: classpath:mapper/*.xml
2.2编写application.properties
mybatis.type-aliases-package=com.xinyu.pojo mybatis.mapper-locations=classpath:mapper/*.xml
3.编写config
3.1---UserRealm
package com.xinyu.config; import com.xinyu.pojo.User; import com.xinyu.service.UserService; import org.apache.catalina.security.SecurityUtil; 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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; public class UserRealm extends AuthorizingRealm { @Autowired UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=>授权doGetAuthorizationInfo"); //授权 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //info.addStringPermission("user:add"); 给所有用户添加add权限 //获取当前登陆对象 Subject subject = SecurityUtils.getSubject(); User currentUser = (User)subject.getPrincipal(); //通过返回的SimpleAuthenticationInfo获取user对象 //将从user获取到的权限进行添加到权限管理 info.addStringPermission(currentUser.getPerms()); return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了=>认证doGetAuthenticationInfo"); //从数据库中获取用户名与密码 // String name = "root"; // String password = "123456"; UsernamePasswordToken userToken = (UsernamePasswordToken)token; //链接真实数据库 User user = userService.queryUserByName(userToken.getUsername()); if (user==null){ return null; //UnknownAccountException用户名错误 } //首页 Subject currentSubject = SecurityUtils.getSubject(); Session session = currentSubject.getSession(); session.setAttribute("loginUser",user); // if(!userToken.getUsername().equals(name)){ // return null; // } //密码认证,shiro做 // return new SimpleAuthenticationInfo("",password,""); return new SimpleAuthenticationInfo(user,user.getPwd(),""); } }
3.2---ShiroConfig
package com.xinyu.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.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.swing.*; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { //ShiroFilterFactoryBean---3 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); //添加shiro的内置过滤器 /* * anon: 无需认证就可访问 * authc: 必须认证才能访问 * user: 必须拥有 记住我 功能才能有 * perms: 拥有对某个资源权限才能访问 * role: 拥有某个角色权限才能访问 * */ //拦截 Map<String,String> filterMap = new LinkedHashMap<>(); // filterMap.put("/user/add","authc"); // filterMap.put("/user/update","authc"); //授权,正常情况下没有授权跳转到未授权界面401 filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/update","perms[user:update]"); filterMap.put("/user/*","authc"); bean.setFilterChainDefinitionMap(filterMap); //设置登陆界面 bean.setLoginUrl("/toLogin"); //未授权界面 bean.setUnauthorizedUrl("/noauth"); return bean; } //@Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常 //@Qualifier限定描述符除了能根据名字进行注入,更能进行更细粒度的控制如何选择候选者 //DafaultWebSecurityManager---2 @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 关联userRealm securityManager.setRealm(userRealm); return securityManager; } //创建reaml对象,需要自定义类---1 @Bean(name = "userRealm") public UserRealm userRealm(){ return new UserRealm(); } //整合shiroDialect用来整合shiro thymeleaf @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } }
4.编写controller--MyController
package com.xinyu.controller; import org.apache.catalina.Session; import org.apache.catalina.security.SecurityUtil; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.rmi.activation.UnknownObjectException; import java.security.Security; @Controller public class MyController { @RequestMapping({"/","/index"}) public String toIndex(Model model) { model.addAttribute("msg","hello,Shiro"); return "index"; } @RequestMapping("/user/add") public String add() { return "user/add"; } @RequestMapping("/user/update") public String update() { return "user/update"; } @RequestMapping("/toLogin") public String toLogin() { return "login"; } @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); //执行登录的方法,没有异常说明ok return "index"; }catch (UnknownAccountException e){ model.addAttribute("msg","用户名错误"); return "login"; }catch (IncorrectCredentialsException e){ model.addAttribute("msg","密码错误"); return "login"; } } @RequestMapping("noauth") @ResponseBody public String unauthorized(){ return "未经授权,无法访问此页面"; }}
5.html页面---index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <div> <h1>首页</h1> <div th:if="${session.get('loginUser')==null}"> <p><a th:href="@{/toLogin}">登录</a></p> </div> <p th:text="${msg}"></p> <hr> <div shiro:hasPermission="user:add"> //更具权限显示 <a th:href="@{/user/add}">add</a> </div> <div shiro:hasPermission="user:update"> <a th:href="@{/user/update}">update</a> </div> </div> </body> </html>
Swagger
Swagger 是一个规范且完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务
导入架包
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.10.0</version> </dependency> <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency>
编写配置文件SwaggerConfig
@Configuration ////加载到配置里面 @EnableSwagger2 //开启Swagger2 public class SwaggerConfig { //Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger @Bean public Docket docket(){ return new Docket(DocumentationType.SWAGGER_2)//配置了Swaggerbean实例 .apiInfo(apiInfo());//重新配置了默认的文档信息 } //配置Swagger信息=apiInfo public ApiInfo apiInfo(){ Contact contact = new Contact("小七","http://xinyu.com","123");//作者信息 return new ApiInfo( "歆鱼的springboot学习笔记", "风雨飘渺,终见曙光", "v1.0", "http://xinyu.com", contact, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList()); } }
测试运行:http://localhost:8080/swagger-ui.html
可能遇到的问题:
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
解决:
在配置文件application.properties中加入以下配置
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
如果是application.yml就加入
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
配置扫描接口
//Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger @Bean public Docket docket(){ return new Docket(DocumentationType.SWAGGER_2)//配置了Swaggerbean实例 .apiInfo(apiInfo())//重新配置了默认的文档信息 .enable(false) //是否启用Swagger,为false,swagger不能再浏览器使用 .select() //RequestHandlerSelectors 要扫描接口的方式 //basePackage() 指定要扫描的包 //any() 扫描全部 //none() 不扫描 //withClassAnnotation() 扫描类上的注解,需要注解的反射对象 //withMethodAnnotation() 扫描方法上注解 //只会扫描有ResrController注解的类.生成一个接口 .apis(RequestHandlerSelectors.basePackage("com.xinyu.controller")) .paths(PathSelectors.ant("/xinyu/**"))//过滤路径 .build();//工厂模式 }
设置在某些环境可以使用swagger,在某些环境下不能使用swagger
1.配置application.properties
#激活dev环境
spring.profiles.active=dev
2.配置application-dev.properties
#正式发布-生产环境 server.port=8081
3.配置application-pro.properties
#测试环境 server.port=8082
4.修改docket的Bean实例
@Bean public Docket docket(Environment environment){ //设置可以使用swagger的环境 Profiles profiles = Profiles.of("dev","test"); //获取环境 //通过environment.acceptsProfiles判断是否出来自己设定的环境 boolean flag = environment.acceptsProfiles(profiles);//获得监听的对象 //配置了Swaggerbean实例 return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo())//重新配置了默认的文档信息 //是否启用swagger,false浏览器不能访问nswagger .enable(flag) .select() .apis(RequestHandlerSelectors.basePackage("com.xinyu.controller")) .build(); }
API分组
@Bean public Docket docket(Environment environment){ return new Docket(DocumentationType.SWAGGER_2)//配置了Swaggerbean实例 .apiInfo(apiInfo()) .groupName("xinyu") } //配置多个Docket
@Bean public Docket docket1(){ return new Docket(DocumentationType.SWAGGER_2) .groupName("xiaoqi"); }
@Bean public Docket docket2(){ return new Docket(DocumentationType.SWAGGER_2) .groupName("kuangshen"); }
编写实体类
@ApiModel("用户实体类") //给实体类添加注释 public class User { @ApiModelProperty("用户名") public String username; @ApiModelProperty("密码") public String password; }
编写控制类测试
@Api("Hello控制类") @RestController public class HelloController { @RequestMapping(value = "/hello") public String hello(){ return "hello"; } //只要我们的接口中,返回值中存在实体类,他就会被扫描到 @PostMapping("/user") public User user(){ return new User(); } //Opertation接口,不是放在类上的,是方法 @ApiOperation("hello控制类") @GetMapping("/hello2") public String hello2(@ApiParam("用户名")String username){ return "hello"+username; } //Opertation接口,不是放在类上的,是方法 @ApiOperation("post控制类") @GetMapping("/post") public User postt(@ApiParam("用户名")User user){ return user; } }
常用注解
Swagger的所有注解定义在io.swagger.annotations包下
总结:
1.可以通过Swagger给一些比较难理解的属性或接口添加注释信息
2.接口文档实时更新
3.可以在线测试
异步任务
service层
@Service public class AsynService { //告诉Spring这是一个异步的方法 @Async public void hello(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("数据正在处理"); } }
编写控制controller层
@RestController
public class AsynController {
@Autowired AsynService asynService;
@RequestMapping("/hello")
public String hello(){
asynService.hello();//停止三秒钟
return "ok";
}
}
开启
//开启异步功能 @EnableAsync @SpringBootApplication public class SpringBoot09Application { public static void main(String[] args) { SpringApplication.run(SpringBoot09Application.class, args); } }
邮件发送
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
编写邮箱
1.在application.properties配置
spring.mail.username=xxxxxx@qq.com spring.mail.password=xxxxxxxxxx spring.mail.host=smtp.qq.com #开启加密验证 spring.mail.properties.mail.smtp.ssl.enable=true
2.在启动类(XxxxApplication )中设置
import javax.mail.internet.MimeMessage; @SpringBootTest class SpringBoot09ApplicationTests { @Autowired JavaMailSenderImpl mailSender; //简单的邮件 @Test void contextLoads() { SimpleMailMessage mailMessage = new SimpleMailMessage(); mailMessage.setSubject("你好呀"); mailMessage.setText("哈哈哈哈哈哈"); mailMessage.setTo("xxxxxx@qq.com"); mailMessage.setFrom("xxxxxx@qq.com"); mailSender.send(mailMessage); } }
发送复杂文件(启动类中设置)
//复杂的邮件 @Test void contextLoads2() throws MessagingException { //一个复杂的邮件 MimeMessage mimeMessage = mailSender.createMimeMessage(); //组装 //正文 MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true); messageHelper.setSubject("你好哇"); //true 支持html messageHelper.setText("<p style='color:red'>歆鱼</p>",true); //附件 messageHelper.addAttachment("1.jpg",new File("D:\\java\\SpringBoot\\xxx\\1.jpg")); messageHelper.setTo("xxxx1@qq.com"); messageHelper.setFrom("xxxx@qq.com"); mailSender.send(mimeMessage); }
定时任务
在启动类设置
@EnableScheduling //开始定时功能的主角 public class SpringBoot09Application {
编写service
@Service public class ScheduledService{ //在一个特定的时间执行这个方法 //秒 分 时 日 月 周 @Scheduled(cron = "20 13 10 * * 0-7") //每天10:13 20执行 public void hello(){ System.out.println("hello,你被执行了~"); } }
(1)0/2 * * * * ? 表示每2秒 执行任务 (1)0 0/2 * * * ? 表示每2分钟 执行任务 (1)0 0 2 1 * ? 表示在每月的1日的凌晨2点调整任务 (2)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业 (3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作 (4)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 (5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 (6)0 0 12 ? * WED 表示每个星期三中午12点 (7)0 0 12 * * ? 每天中午12点触发 (8)0 15 10 ? * * 每天上午10:15触发 (9)0 15 10 * * ? 每天上午10:15触发 (10)0 15 10 * * ? 每天上午10:15触发 (11)0 15 10 * * ? 2005 2005年的每天上午10:15触发 (12)0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发 (13)0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发 (14)0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 (15)0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发 (16)0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发 (17)0 15 10 ? * MON-FRI 周一至周五的上午10:15触发 (18)0 15 10 15 * ? 每月15日上午10:15触发 (19)0 15 10 L * ? 每月最后一日的上午10:15触发 (20)0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发 (21)0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发 (22)0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
Dubbo
学习文档:https://blog.csdn.net/will_be_better/article/details/122673681
RPC核心:通讯,序列化
Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心