赞
踩
接上一篇springboot基础框架搭建。
对于数据库访问层,SpringBoot底层都是采用Spring Data的方式进行统一处理
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
然后在测试中测试链接
package com.ckl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.sql.DataSource;
@SpringBootTest
class SpringbootDataApplicationTests {
@Autowired
DataSource dataSource;
@Test
void contextLoads() {
System.out.println(dataSource.getClass());
//输出数据源:class com.zaxxer.hikari.HikariDataSource
}
}
使用JDBCTemplate
新建一个JDBCController.java,用jdbcTemplate实现增删查改
@RestController//return的不在是跳转作用,而是返回字符串
public class JDBCController {
@Autowired
JdbcTemplate jdbcTemplate;
//查询数据库的所有信息
//没有实体类 获取数据库中的东西
@GetMapping("/courseList")
public List<Map<String,Object>> userList(){
String sql = "select * from course";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
return maps;//返回数据库表中所有信息
}
@GetMapping("/addCourse")
public String addCourse(){
String sql = "insert into test.course(c_id,c_name,t_id) values(5,'生物','05')";
int i = jdbcTemplate.update(sql);
return i+"";
}
@GetMapping("/updateCourse/{c_id}")
public String updateCourse(@PathVariable("c_id") int c_id){
String sql = "update test.course set c_name = ?,t_id = ? where c_id = " + c_id;
//封装
Object[] objects = new Object[2];
objects[0] = "地理";
objects[1] = "01";
jdbcTemplate.update(sql,objects);
return "ok!";
}
@GetMapping("/deleteCourse/{c_id}")
public String deleteCourse(@PathVariable("c_id") int c_id){
String sql = "delete from test.course where c_id = ?";
jdbcTemplate.update(sql,c_id);
return "deleteOk";
}
}
数据库连接池,加入了日志监控。Github地址:https://github.com/alibaba/druid/
<!--Druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#指定数据源:Druid
#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
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
@Configuration
public class DruidConfig {
//将其余application.yaml文件绑定:datasource
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidSource(){
return new DruidDataSource();
}
//后台监控功能,相当于web.xml ==> ∵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");//登录key:loginUsername :固定写法,不能改变
initParameters.put("loginPassword","123");
//允许谁可以访问
initParameters.put("allow","localhost");//后面的“”如果为空,所有人就都可以访问
//禁止谁能访问
initParameters.put("kalen","192.168.0.125");
//后台需要登录,账号密码配置
bean.setInitParameters(initParameters);//初始化参数 (Map参数)
return bean;
}
//filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());//设置过滤器
HashMap<String,String> initParameters = new HashMap<>();
initParameters.put("exclusions","*.js,*.css,/druid/*");//这些路径下的不进行统计
bean.setInitParameters(initParameters);
return bean;
}
}
访问:http://localhost:8080/druid/login.html
登录进入之后
创建SpringBoot新项目,添加spring-jdbc,mysql-server,web依赖
添加mybatis依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
在application.properties配置文件中配置数据库连接信息
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
user.java:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class user {
private Integer id;
private String name;
private String pwd;
}
@Mapper //表示这是一个MyBatis的Mapper类
//或者在启动类Application上加上@MapperScan("com.ckl.mapper") :扫描路径下的文件
@Repository //dao层
public interface UserMapper {
List<user> queryUserList();
user queryUserBuId(int id);
int addUser(user u);
int updateUser(user u);
int deleteuser(int id);
}
```
##### 3.在resource目录下新建mybatis/mapper目录
然后创建UserMapper.xml(编写sql)
```xml
<?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.ckl.mapper.UserMapper">
<select id="queryUserList" resultType="user">
select * from test.user;
</select>
<select id="queryUserById" resultType="user">
select * from test.user where id = #{id};
</select>
<insert id="addUser" parameterType="user">
insert into test.user(id,name,pwd) values (#{id},#{name},#{pwd});
</insert>
<update id="updateUser" parameterType="user">
update test.user set name=#{name},pwd=#{pwd} where id=#{id};
</update>
<delete id="deleteuser" parameterType="int">
delete from test.user where id=#{id};
</delete>
</mapper>
然后在application.properties中整合mybatis:
这样就可以将xm与dao联系起来
#整合mybatis
mybatis.type-aliases-package=com.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
然后创建UserController.java
实现具体业务
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/user/queryUserList")
public List<user> queryUserList(){
List<user> users = userMapper.queryUserList();
return users;
}
...
}
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
WebSecurityConfigurerAdapter:自定义Security策略
AuthenticationManagerBuilder:自定义认证策略
@EnableWebSecurity:开启WebSecurity模式
<dependencies>
<!--spring security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
SpringSecurity静态资源及项目:
链接:https://pan.baidu.com/s/1Wjk17e6UYPN3DDEP7DDv2w 提取码:qoto
一个路由controller 用于跳转各种页面.RouterController.java:
@Controller
public class RouterController {
//跳转首页
@RequestMapping({"/","/index"})
public String index(){
return "index";
}
//跳转login
@RequestMapping("toLogin")
public String toLogin(){
return "views/Login";
}
//跳转到level1
@RequestMapping("/level1/{id}")
public String level1(@PathVariable("id") int id){
return "views/level1/"+id;
}
//跳转到level2
@RequestMapping("/level2/{id}")
public String level2(@PathVariable("id") int id){
return "views/level2/"+id;
}
//跳转到level3
@RequestMapping("/level3/{id}")
public String level3(@PathVariable("id") int id){
return "views/level3/"+id;
}
}
SecurityConfig类
Security配置类,进行配置相关处理
//AOP 横切
@EnableWebSecurity // 开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//http安全策略
//链式编程
@Override
protected void configure(HttpSecurity http) throws Exception {//授权认证
//首页所有人可以访问,功能页只有对应有权限的人可以访问
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
// 开启自动配置的登录功能
// /login 请求来到登录页
// /login?error 重定向到这里表示登录失败
http.formLogin();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {//权限认证
//需要对密码进行加密
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("ckl").password(new BCryptPasswordEncoder().encode("123")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("789")).roles("vip1","vip2");
/*不加密报错
* auth.inMemoryAuthentication()
.withUser("ckl").password("123").roles("vip2","vip3")
.and()
.withUser("root").password("456").roles("vip","vip2","vip3")
.and()
.withUser("guest").password("255").roles("vip1");
* */
}
}
测试,登录成功,并且每个角色只能访问自己认证下的规则。
SecurityConfig.java
@Override
protected void configure(HttpSecurity http) throws Exception {//授权认证
...
//开启注销(跳转到登录)
//http.logout();
// 然后实现跳转到首页
http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
http.logout().logoutSuccessUrl("/");
}
<!--security-thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
SecurityConfig.java
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {//权限认证
//需要对密码进行加密
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("ckl").password(new BCryptPasswordEncoder().encode("123")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("789")).roles("vip1","vip2");
/*不加密报错
* auth.inMemoryAuthentication()
.withUser("ckl").password("123").roles("vip2","vip3")
.and()
.withUser("root").password("456").roles("vip","vip2","vip3")
.and()
.withUser("guest").password("255").roles("vip1");
* */
}
index.html
<a class="item" th:href="@{/index}">首页</a>
<!--登录注销-->
<div class="right menu">
<!--如果未登录-->
<div sec:authorize="!isAuthenticated()">
<a class="item" th:href="@{/login}">
<i class="address card icon"></i> 登录
</a>
</div>
<!--如果已登录-->
<div sec:authorize="isAuthenticated()">
<a class="item">
<i class="address card icon"></i>
用户名:<span sec:authentication="principal.username"></span>
角色:<span sec:authentication="principal.authorities"></span>
</a>
</div>
<div sec:authorize="isAuthenticated()">
<a class="item" th:href="@{/logout}">
<i class="address card icon"></i> 注销
</a>
</div>
</div>
index.html
<!--动态菜单的效果-->
<!-- sec:authorize="hasRole('vip1')" -->
<div class="column" sec:authorize="hasRole('vip1')">
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 1</h5>
<hr>
<div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
<div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
<div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
</div>
</div>
</div>
</div>
<div class="column" sec:authorize="hasRole('vip2')">
...
</div>
SecurityConfig.java
protected void configure(HttpSecurity http) throws Exception {//授权认证
protected void configure(HttpSecurity http) throws Exception {
...
//记住我
http.rememberMe();//cookie 默认保存2周
}
}
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-lang -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-lang</artifactId>
<version>1.5.1</version>
</dependency>
<!-- configure logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.26</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.26</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<Configuration name="ConfigTest" status="ERROR" monitorInterval="5">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="org.springframework" level="warn" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.apache" level="warn" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="net.sf.ehcache" level="warn" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.apache.shiro.util.ThreadContext" level="warn" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
在idea中需要下载ini插件,不然ini就是text文档
[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
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.ini.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.lang.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple Quickstart application showing how to use Shiro's 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 currentUser = SecurityUtils.getSubject();
// Do some stuff with a Session (no need for a web or EJB container!!!)
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()) {
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);
}
}
因为shrio用的不多,所以就不详细记载了
官网:https://swagger.io/
在项目中使用swagger,需要springbox(jar包):swagger2,swagger ui
<!-- springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
测试项目是否能够正常运行
SwaggerConfig.java
@Configuration //加上这个注解,就会加载到配置中。等价于 @Component
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
//默认配置
}
http://localhost:8080/swagger-ui.html ,得到下面这个页面
swagger的Bean实例 Docket
@Configuration //加上这个注解,就会加载到配置中。等价于 @Component
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
//配置swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfos());
}
//配置swagger信息 => apiInfo
private ApiInfo apiInfos(){
//作者信息
Contact contact = new Contact("小陈", "http://localhost:8080/hello", "123456@qq.com");
return new ApiInfo("kalen的Swagger API文档",
"长风破浪",
"v1.0",
"http://localhost:8080",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
然后访问http://localhost:8080/swagger-ui.html ,得到下面这个页面
@Configuration //加上这个注解,就会加载到配置中。等价于 @Component
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
//配置swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfos()) //RequestHandlerSelectors , 配置要扫描接口的方法;basePackage :指定要扫描的包
.select().apis(RequestHandlerSelectors.basePackage("com.ckl.controller")).build();
}
@Configuration //加上这个注解,就会加载到配置中。等价于 @Component
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
//配置swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfos())
.enable(true)//启动swagger
.select().apis(RequestHandlerSelectors.basePackage("com.ckl.controller")).build();
}
.groupName(" ")
@Configuration //加上这个注解,就会加载到配置中。等价于 @Component
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
//配置swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfos())
.groupName("ckl")
.enable(true)
.select().apis(RequestHandlerSelectors.basePackage("com.ckl.controller")).build();
}
@Configuration //加上这个注解,就会加载到配置中。等价于 @Component
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
//配置多个Docket
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("kalen");
}
//配置swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfos())
.groupName("ckl")
...
}
}
此时在右上角的文本框中,下拉列表就会出现两个值“kalen” “ckl”,
选中哪个值,就相当于选择哪个Docket,此时kalen这个Docket什么都没有配置,就显示默认的
User.java
public class User {
private String username;
private String password;
}
HelloController.java
@RestController
public class HelloController {
...
//只要我们的接口返回值中有实体类,就会被扫描
@PostMapping(value = "/usero")
public User user(){
return new User();
}
}
相当于注释,别名
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private String password;
}
字段用public修饰时,就可以显示出来;private修饰不能显示出来
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
public String username;
@ApiModelProperty("密码")
public String password;
}
@ApiOperation() @ApiParam
@ApiOperation() 只能应用于方法上面 ; @ApiParam 给参数加注释
@RestController
public class HelloController {
@ApiOperation("Hello控制类")
@GetMapping(value = "/hello2")
public String hello2(@ApiParam("username注释") String username){
return "ok"+username;
}
...
}
1.我们可以通过swagger,给一些比较难理解的属性或者接口,增加注释信息
2.接口文档实时更新
3.可以在线测试
在项目正式发布时,需要关闭swagger,保证项目的安全性
HelloService.java
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据正在处理...");
}
}
AsyncController.java
import com.ckl.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AsyncController {
@Autowired
AsyncService asyncService;
@RequestMapping("/hello")
public String hello(){
asyncService.hello();
return "OK";
}
}
此时访问:http://localhost:8080/hello 网页会先转3秒,然后才能进入
为了使用户在接收消息的同时,又不等待消息。所以就需要异步来提升用户体验
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
//告诉Spring这是一个异步的方法
@Async
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据正在处理...");
}
}
启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync //开启异步功能
@SpringBootApplication
public class Springboot0609Application {
public static void main(String[] args) {
SpringApplication.run(Springboot0609Application.class, args);
}
}
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
在配置文件中,进行配置
#邮箱配置 163:XFQMYTYRXNKNBVBJ
spring.mail.username=2xxxx84@qq.com
spring.mail.password=授权码
#获取授权码:在邮箱中的设置->账户->开启pop3和smtp服务
spring.mail.host=smtp.qq.com
#开启加密验证
#qq邮箱有,网易邮箱没有
spring.mail.properties.mail.smtp.ssl.enable=true
然后在测试中,就可以完成
@SpringBootTest
class Springboot0609ApplicationTests {
@Autowired
JavaMailSenderImpl mailSender;
@Test
public void contextLoads() {
//邮件设置1:一个简单的邮件
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("通知-");
message.setText("今晚7:30开会");
message.setTo("kalenxxx@163.com");
message.setFrom("25xxxx4@qq.com");
mailSender.send(message);
}
@Test
public void contextLoads2() throws MessagingException {
//邮件设置:一个复杂的邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装:
//正文
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"utf-8");
helper.setSubject("kalen");
helper.setText("<p style='color:red'>hello,kalen</p>",true);
//附件
helper.addAttachment("1.png",new File("D:\....png"));
//File:可以是绝对路径
helper.setTo("kalenxxx@163.com");
helper.setFrom("25xxx@qq.com");
mailSender.send(mimeMessage);
}
}
ScheduledService.java
@Scheduled
@Service
public class ScheduledService {
//"0 * * * * 0-7" :秒 分 时 日 月 周几
//"0 40 15 * * ?" :每天的15.40.0执行
//"30 0/5 15,16 * * ?" : 每天的15点16点 每隔5分钟执行一次
@Scheduled(cron = "0 40 15 * * ?") //@Scheduled(时间表达式)
public void hello(){
System.out.println("******************************");
System.out.println("在特定的时间被执行了~");
}
}
启动类
@EnableScheduling
@SpringBootApplication
@EnableScheduling //开启定时功能注解
public class Springboot0609Application {
public static void main(String[] args) {
SpringApplication.run(Springboot0609Application.class, args);
}
}
【右侧maven->项目名->Lifecycle->package生成jar包】可以配置打包时 跳过项目运行测试用例
<!--
在工作中,很多情况下我们打包是不想执行测试用例的
可能是测试用例不完事,或是测试用例会影响数据库数据
跳过测试用例执
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--跳过项目运行测试用例-->
<skipTests>true</skipTests>
</configuration>
</plugin>
添加依赖 pom.xml
<!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
页面拿不到数据时:
mvc自动配置的静态视图错误:无法为请求[/emps]这个页面和异常[]呈现错误页面。仔细查看了一下这个页面的编写,原来前端在获取后端的主键时写错了参数,以至于报错。
java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required
将mysql依赖版本降低同时在配置文件中改为以前的:driver-class-name: com.mysql.jdbc.Driver
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
在创建maven项目时,点击finish后却弹出连接超时
==》查看一下maven应用的是自己的配置还是idea自带的。配置阿里云镜像
在UserMapper.xml文件中 要将user路径写完成,写全限定名
在https://start.spring.io/中的https改成http ,在这处
访问: https://repo.maven.apache.org/maven2 将jar包下全
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userServiceImpl': Unsatisfied dependency expressed through field 'userDao';
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'userDao' defined in file [E:\Idea\springboot_demo_0602\target\classes\com\ckl\dao\UserDao.class]:
Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
当发现错误时,在mvc三层架构中,都检查了注解 @Mapper @Service @Controller 在启动类上@MapperScan(“xxx.xx.dao”) 在配置文件中配置路径:
#mapper路径配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.ckl.pojo
但是都没有效果,最后检查了一下pom.xml依赖,发现包引入错误错误之前引入的是:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
但真正需要的依赖时下面一个依赖,而不是上面的两个依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
mybatis-spring-boot-starter就包含了上面两个依赖,并且在这个依赖中,会自动配置sqlSessionFactory
又是导包问题
<!--Druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
下面的依赖包含上面的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
2022-06-11 22:08:12.536 ERROR 23272 --- [reate-691854979] com.alibaba.druid.pool.DruidDataSource : create connection SQLException, url: jdbc:mysql://127.0.0.1:3306/employeedemo?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true, errorCode 0, state 08001
java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110) ~[mysql-connector-java-8.0.29.jar:8.0.29]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.29.jar:8.0.29]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89) ~[mysql-connector-java-8.0.29.jar:8.0.29]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63) ~[mysql-connector-java-8.0.29.jar:8.0.29]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:73) ~[mysql-connector-java-8.0.29.jar:8.0.29]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:79) ~[mysql-connector-java-8.0.29.jar:8.0.29]
降低版本:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.49</version>
</dependency>
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Jun 13 10:35:23 CST 2022
There was an unexpected error (type=Internal Server Error, status=500).
2022-06-13 10:35:23.588 ERROR 15420 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ckl.dao.DEvoDao.FindAll] with root cause
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ckl.dao.DEvoDao.FindAll
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:227) ~[mybatis-3.4.6.jar:3.4.6]
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:49) ~[mybatis-3.4.6.jar:3.4.6]
at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65) ~[mybatis-3.4.6.jar:3.4.6]
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58) ~[mybatis-3.4.6.jar:3.4.6]
at com.sun.proxy.$Proxy61.FindAll(Unknown Source) ~[na:na]
at com.ckl.service.impl.DEvoServiceImpl.FindAll(DEvoServiceImpl.java:23) ~[classes/:na]
at com.ckl.controller.DEvoController.FindAll(DEvoController.java:28) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.20.jar:5.3.20]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.20.jar:5.3.20]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.20.jar:5.3.20]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.20.jar:5.3.20]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.20.jar:5.3.20]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.20.jar:5.3.20]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.20.jar:5.3.20]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.20.jar:5.3.20]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) ~[tomcat-embed-core-9.0.63.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.20.jar:5.3.20]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.63.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.63.jar:9.0.63]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123) ~[druid-1.1.9.jar:1.1.9]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.20.jar:5.3.20]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.20.jar:5.3.20]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.20.jar:5.3.20]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.63.jar:9.0.63]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.63.jar:9.0.63]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]
```
##### 13.添加swagger后,启动服务报错
```java
Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.20.jar:5.3.20]
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.20.jar:5.3.20]
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.20.jar:5.3.20]
at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_131]
解决方法:
在配置文件中添加配置:
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。