能创建独立的Spring Boot应用
嵌入Tomcat,Jetty Undertow而且不需要部署他们
提供的“starters” poms来简化Maven配置
https://www.cnblogs.com/qlqwjy/p/7979159.html
Spring将很多魔法带入了Spring应用程序的开发之中,其中最重要的是以下四个核心。
- 自动配置:针对很多Spring应用程序常见的应用功能,Spring Boot能自动提供相关配置
- 起步依赖:告诉Spring Boot需要什么功能,它就能引入需要的库。
- 命令行界面:这是Spring Boot的可选特性,借此你只需写代码就能完成完整的应用程序,无需传统项目构建。
- Actuator:让你能够深入运行中的Spring Boot应用程序,一探究竟。
尽可能自动配置Spring应用
提供生产指标,健壮检查和外部化配置
在spring boot出现之前,使用spring框架时需要大量的xml配置,现在则可以仅需要少量的配置或无需配置
Spring的目标不在于为己解决的问题领域提供新的解决方案,而是为平台带来一种新的开发体验,从而简化对这些已有技术的使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PjiW834j-1638550633743)(SpringBoot.assets/image-20210420104137977.png)]
通过maven引入springboot-XXXX-starter
修改yml或properties全局统一配置文件
加入一个Java Config。这个属于个性化配置,如果使用通用配置,这一步不需要。
Spring Boot Starter是一组被依赖第三方类库的集合
如开发WEB应用,引入Spring-boot-starter-web即可,该starter会自动引入如下类库:
Spring ——spring核心,baens,context上下文,AOP面向切面
Web MVC ——Spring MVC
Jackson —— JSON 数据的序列化与反序列化
嵌入式Servlet Container ——Tomcat
日志框架Loggin——logback,slf4j
自行百度
也可以直接把web环境添加进去 ——自行百度
boot 自带LOG_PATH 日志
目录位置 | 功能 |
---|---|
src / main / java | 项目的java文件存放位置,初始化包包含主程序入口 XXXApplication,可以通过直接运行该类来启动Srping Boot应用 |
src / main / resources | 存放静态资源,图片、CSS、javaScript、web页面模板文件等 |
src / test | 单元测试代码目录 |
.gitignore | git版本管理排除文件 |
target 文件夹 | 项目代码构建打包结果文件存放位置,不需要认为维护 |
pom.xml | maven项目配置文件 |
application.properties (application.yml) |
用于存放程序各种依赖模块的配置信息,比如服务器端口,数据库连接配置等 |
src / main / resources / static | 主要用于存放CSS、图片、js等开发用到的静态文件 |
src / main / resources / pulic | 用来存放可以直接用于访问的html文件 |
src / main / resources / templa | 用于存放web开发模板文件 |
### devtools实现热加载
依赖(创建工程时如没有勾选则加入如下依赖)
org.springframework.boot
spring-boot-devtools
true
设置IDEA
代码修改后
处理用户请求
类似于Servlet,但比Servlet更加方便灵活,自动完成了很多工作
自动接收请求参数
类型转换
数据验证
@Controller
将bean定义为控制器
@RestController
RestConntroller相当于@Controller与@ResponseBody结合
- Controller 将控制器类注入到Spring上下文环境中,该类RequestMapping标注为HTTP服务端点
- ResponseBody的作用,请求响应默认使用的序列化方式是JSON,而不是跳转到jsp或模板页面。
@RequestMapping注解
@RequestBody与@ResponseBody
@RequestBody修饰请求参数,注解用于接收HTTP的body,默认是使用JSON的格式,能够使用对象或者嵌套对象接收前端数据
@ResponseBody修饰返回值,注解用于在HTTP的body中携带响应数据,默认是使用JSON的格式。如果不加该注解,spring响应字符串类型,是跳转到模板页面或jsp页面的开发模式。即加上这个注解开发的是一个数据接口,不加这个注解开发的是一个页面跳转控制器。
@ResponseBody的作用其实是将java对象转为json格式的数据。当请求为PUT与DELETE时一定需要加上该注解。注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。@GetMapping("/toIndex4") //加上@ResponseBody表示返回的是字符串或者json @ResponseBody public UserVo toIndex4(){ UserVo user = new UserVo(); user.setUid(11); user.setPwd("ss"); user.setUname("许仙"); return user; }
@ModelAttribute
@ModelAttribute主要的作用是将数据添加到模型对象中,用于视图页面显示。
@PathVariable 与@RequestParam
@PathVariable用于URI上的{参数},如下方法用于删除一篇文章,其中id为文章id。如:我们的请求URL为“/article/1”,那么将匹配DeleteMapping并且PathVariable接收参数id=1;@PathVariable用于将请求RESTFUL风格的URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数
而RequestParam用于接收普通表单方式或者ajax模拟表单提交的参数数据。
@DeleteMapping("/article/{id}")
public @ResponseBody AjaxResponse deleteArticle(@PathVariable Long id)
@PostMapping("/article")
public @ResponseBody AjaxResponse deleteArticle(@RequestParam Long id)
@GetMapping("/toIndex")
// 将它接收到的un参数名称绑定到别名uname中去
public ModelAndView toIndex2(@RequestParam("un")String uname){
ModelAndView mv = new ModelAndView("index");
mv.addObject("uname",uname);
return mv;
}
RequestMapping
@PostMapping等同于@RequestMapping的method等于POST。
@GetMapping等同于@RequestMapping的method等于GET。
@PutMapping等同于@RequestMapping的method等于PUT。
@DeleteMapping等同于@RequestMapping的method等于DELETE。
相当于get或者post等传过来的参数,
相当于路径上的值
/**
* @author XuLuBao
* @version V1.0
* @Package com.trkj.boot1.controller
* @date 2021/4/20 16:11
*/
@Log4j2
@RestController
//相当于这两个的作用 @Controller + @ResponseBody
public class RestFulController {
@GetMapping("/user/{id}")
public UserVo findUser(@PathVariable("id")int id){
UserVo vo = new UserVo();
vo.setUname("许仙");
vo.setUid(1);
log.debug("获取成功");
return vo;
}
@DeleteMapping("/user/{uid}/{na}")
public String delUser(@PathVariable("uid")int id,@PathVariable("na")String na){
System.out.println(id+na);
log.debug("删除成功");
return "成功删除!";
}
@PutMapping("/user")
// 对应起来
public String alertUser( @RequestBody UserVo vo){
log.debug("修改成功");
return "成功修改";
}
@PostMapping("/user")
public UserVo addUser(@RequestBody UserVo vo){
vo.setPwd("ss");
log.debug("添加成功");
return vo;
}
}
1. 返回String,用于表示视图名称,如需要向客户端返回数据,可配合方法参数中的Model对象来使用。或者使用@ModelAttribute(“xx”)可直接针对参数给定别名后向Model添加对应的值。
2. 返回String,用于表示直接向客户端返回字符串结果,此时并不是返回视图,而是直接返回数 据。该字符串可以是普通字符串,也可以Json格式字符串。需要在方法上使用```<@ResponseBody>```注解。
3. 返回ModelAndView,视图加数据,如需要向客户端返回数据时,用```ModelAndView```将会比较方便。
普通参数
参数为JavaBean对象
接收Date类型的参数,默认情况下只支持yyyy/dd/mm格式的日期
RESTFul风格的方式参数
默认情况下是转发,如果是重定向,返回结果添加 redirect前缀
@RequestMapping("redirect")
public String redirect(){
return "redirect:/hello.jsp";
}
案列
@PostMapping("/show")
// 也会帮我封装好了,添加@ModelAttribute("user")只是往作用域里面添加了数据用于访问
public String toShowUser(UserVo user, Model model){
user.setPwd("15111666207");
// 相当于自动往作用域里面存放值,boot自动帮我做了这些事
//
model.addAttribute("vo",user);
return "show";
}
SessionAttributes 在运行之前会对参数名称为“user”的参数进行存储到session当中去
在需要对他进行清楚的的时候直接在方法中添加:SessionStatus,在方法体中调用 SessionStatus.setComplete();进行清除,但是它只能清除在SessionAttributes中存储的值
@GetMapping(value = "/indexU" )
public String chkLong(User user,SessionStatus status) {
if (user!=null&&user.getName()!=null) {
if (user.getName().length()>=6) {
return "index";
}else {
status.setComplete();
return "login";
}
} else {
status.setComplete();
return "login";
}
}
在以上由于在类上添加了,得到的user是已经创建过的对象,但是它里面的值不是空,需要判断对象之后也还要判断属性。
在resources目录中添加logback-spring.xml日志文件,添加相应的日志代码
添加 Maven 相关依赖,这里需要添加上WEB和SWAGGER依赖。
org.springframework.boot
spring-boot-starter-web
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2
添加配置类
添加一个swagger 配置类,在工程下新建 config 包并添加一个 SwaggerConfig 配置类。
SwaggerConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("Kitty API Doc")
.description("This is a restful api document of Kitty.")
.version("1.0")
.build();
}
}
添加一个控制类
/**
* @author XuLuBao
* @version V1.0
* @Package com.trkj.boot1test1.controller
* @date 2021/4/21 15:12
*/
/*方法注解*/
@Api(value = "desc of class")
@RestController
public class TestController {
/*方法注解*/
@ApiOperation(value="desc of method",notes="notes")
@GetMapping
public Object hello(/*参数注解*/@ApiParam(value = "desc of param",required = true)@RequestParam String name){
return "Hello" + name + "!";
}
}
添加配置类
@Configuration
@Slf4j
public class AppCorsConfiguration {
private CorsConfiguration buildConfig() {
log.debug("开始设置");
CorsConfiguration appCorsConfiguration = new CorsConfiguration();
appCorsConfiguration.addAllowedOrigin("http://localhost:8081");
appCorsConfiguration.addAllowedOrigin("http://127.0.0.1:8081");
appCorsConfiguration.addAllowedHeader("*"); // 2允许任何头
appCorsConfiguration.addAllowedMethod("OPTIONS");
appCorsConfiguration.addAllowedMethod("HEAD");
appCorsConfiguration.addAllowedMethod("GET");
appCorsConfiguration.addAllowedMethod("PUT");
appCorsConfiguration.addAllowedMethod("POST");
appCorsConfiguration.addAllowedMethod("DELETE");
appCorsConfiguration.addAllowedMethod("PATCH");
appCorsConfiguration.setAllowCredentials(true);//这两句不加不能跨域上传文件,
appCorsConfiguration.setMaxAge(3600L);//加上去就可
return appCorsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4
return new CorsFilter(source);
}
}
或者添加
@CrossOrigin
Json Web Token(JWT):JSON网络令牌,是为了在网络应用环境间传递声明而制定的一种基于JSON的开放标准((RFC 7519)。JWT是一个轻便的安全跨平台传输格式,定义了一个紧凑的自包含的方式用于通信双方之间以 JSON 对象行使安全的传递信息。因为数字签名的存在,这些信息是可信的。
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了JWT字符串。
+ >eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
jwt由三部分组成
头部 header
{
“alg”: “HS256”,
“typ”: “JWT”
}
载荷 plyload
该部分一般存放一些有效的信息.有效信息包含了三个部分,标准中注册的声明,共有的声明,私有的声明(即自定义字段)
注册声明是指声明名称已在IANA JSON Web Token注册表中注册并在规范中定义的声明,JWT标准中注册的声明 (建议但不强制使用) 包含七个字段:
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众(接收对象)
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
公有声明是指未在规范中定义但已在IANA JSON Web Token注册表中注册的声明,或者使用防冲突名称命名(例如,包含命名空间)的声明。
私有声明是指没有注册而是由JWT的消费者和生产者自定义的声明。正因为如此,存在名称冲突的可能性。
{
“sub”: “1234567890”,
“name”: “John Doe”,
“iat”: 1516239022
}
签证 signature
签证 JWT最后一个部分.该部分是使用了HS256加密后的数据;包含了三个部分:
hander(base64后的)
payload(base64后的)
secret 私钥
secret是保存在服务器端的,JWT的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,他就是你服务端的密钥,在任何场景都不应该泄露出去.一旦客户端得知了这个secret,那就意味这客户端可以自我签发JWT了.
cookie+session这种模式通常是保存在内存中,而且服务从单服务到多服务会面临的session共享问题,随着用户量的增多,开销就会越大。
cookie+session限制了应用的扩展能力,特别是分布式应用中各服务器如何共享session是一个非常头疼的问题。
JWT只需要服务端生成token,客户端保存这个token,每次请求携带这个token,服务端认证解析就可,减轻了服务器压力。也非常适合分布式应用开发。
JWT是无状态,一次性的。想修改里面的内容,就必须签发一个新的JWT。即缺陷是一旦下发,服务后台无法拒绝携带该jwt的请求(如踢除用户)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6W5Lp87Z-1638550633746)(SpringBoot.assets/image-20210425094857539.png)]
Maven依赖配置
io.jsonwebtoken
jjwt
0.9.1
application.yml配置
jwt:
#密钥key
secret: JWTSecret
#HeaderKEY
header: JWThEADERnAME
#过期时间毫秒
expire: 100
server:
port: 8089
#连接池配置
servlet:
context-path: /jwttest
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3308/mydb?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root2020
driver-class-name: com.mysql.cj.jdbc.Driver
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 配置测试查询语句
validationQuery: SELECT 'x'
# 初始化大小,最小,最大
initialSize: 10
minIdle: 10
maxActive: 200
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 180000
testOnBorrow: false
testWhileIdle: true
removeAbandoned: true
removeAbandonedTimeout: 1800
logAbandoned: true
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxOpenPreparedStatements: 100
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j2
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
redis:
database: 0 # Redis 数据库索引(默认为 0)
host: 127.0.0.1 # Redis 服务器地址
port: 6379 # Redis 服务器连接端口
password: redis2020 # Redis 服务器连接密码(默认为空)
lettuce:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制) 默认 8
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-idle: 8 # 连接池中的最大空闲连接 默认 8
min-idle: 0 # 连接池中的最小空闲连接 默认 0
# JWT配置
jwt:
# 密匙KEY
secret: JWTSecret
# HeaderKEY
header: JWTHeaderName
# Token前缀字符
tokenPrefix: Security-c
# 过期时间毫秒
expire: 100000
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.trkj.jwtdemo.entity
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countS
编写jwtTokenUtil工具类
@Slf4j
@Data
@ConfigurationProperties(prefix = "jwt")
@Component
public class JwtTokenUtil {
private String secret;
private Long expire;
private String header;
/**
* 生成token令牌
*
* @param userName 用户
* @return 令token牌
*/
public String generateToken(String userName) {
Map<String, Object> claims = new HashMap<>(2);
claims.put("sub", userName);
//claims.put("id",user.getId());
claims.put("created", new Date());
return generateToken(claims);
}
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
public String getUsernameFromToken(String token) {
String username;
try {
Claims claims = getClaimsFromToken(token);
username = claims.getSubject();
} catch (Exception e) {
username = null;
}
return username;
}
/**
* 判断令牌是否过期
*
* @param token 令牌
* @return 是否过期
*/
public Boolean isTokenExpired(String token) {
try {
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
log.info("in isTokenExpired date:{}",expiration.toLocaleString());
Date date=new Date();
log.info("in isTokenExpired now:{},exp:{} ,{}",date.toLocaleString(),expiration.toLocaleString(),expiration.before(date));
return expiration.before(date);
} catch (Exception e) {
e.printStackTrace();
return true;
}
}
/**
* 得到token的过期时间,测试用,可删除
* @param token
* @return
*/
public Date expirationDate(String token){
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration;
}
/**
* 刷新令牌
* @param token 原令牌
* @return 新令牌
*/
public String refreshToken(String token) {
String refreshedToken;
try {
Claims claims = getClaimsFromToken(token);
claims.put("created", new Date());
refreshedToken = generateToken(claims);
} catch (Exception e) {
e.printStackTrace();
refreshedToken = null;
}
return refreshedToken;
}
/**
* 验证令牌
*
* @param token 令牌
* @param userName 用户
* @return 是否有效
*/
public Boolean validateToken(String token, String userName) {
String uname = getUsernameFromToken(token);
return (uname.equals(userName) && !isTokenExpired(token));
}
/**
* 从claims生成令牌
* @param claims 数据声明
* @return 令牌
*/
private String generateToken(Map<String, Object> claims) {
Date expirationDate = new Date(System.currentTimeMillis() + expire);
/**
* signWith() 签名方法。两个参数分别是签名算法和自定义的签名Key(盐)。
* 签名key可以byte[] 、String及Key的形式传入。
* 前两种形式均存入builder的keyBytes属性,后一种形式存入builder的key属性。
* 如果是第二种(及String类型)的key,则将其进行base64解码获得byte[] 。
* compact() 生成JWT
*/
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setClaims(claims)
.setExpiration(expirationDate)
.setIssuedAt((Date)claims.get("created"))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
}
编写拦截器TokenInterceptor类
@Slf4j
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {
@Resource
private JwtTokenUtil jwtTokenUtil;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws SignatureException {
/** 地址过滤 */
String uri = request.getRequestURI() ;
System.out.println(uri);
if (uri.contains("/login")){
return true ;
}
/** Token 验证 */
String token = request.getHeader(jwtTokenUtil.getHeader());
if(StringUtils.isEmpty(token)){
token = request.getParameter(jwtTokenUtil.getHeader());
}
if(StringUtils.isEmpty(token)){
throw new SignatureException(jwtTokenUtil.getHeader()+ "不能为空");
}
if(jwtTokenUtil.isTokenExpired(token))
throw new SignatureException(jwtTokenUtil.getHeader() + "失效,请重新登录。");
/** 设置 identityId 用户身份ID */
// request.setAttribute("identityId", jwtTokenUtil.getUsernameFromToken(token));
return true;
}
}
注册拦截器
@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private TokenInterceptor tokenInterceptor ;
public void addInterceptors(InterceptorRegistry registry) {
log.debug("注册TokenInterceptor");
registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
}
}
编写控制器
@Slf4j
@RestController
public class IndexController {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@PostMapping("/login")
public AjaxResponse login(@RequestBody User user){
log.info(user.toString());
String token=jwtTokenUtil.generateToken(user.getName(),user.getId()+"");
return AjaxResponse.success(token);
}
@GetMapping("/user/{id}")
public AjaxResponse findUser(@PathVariable("id") int id){
log.info("FindUser........................");
User user=new User();
user.setId(id);
user.setName("TestName");
user.setPwd("testPwd");
return AjaxResponse.success(user);
}
}
PostMan测试与VUE测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-292RcHSC-1638550633747)(SpringBoot.assets/image-20210429142405443.png)]
基本依赖、数据库依赖、数据源依赖
......
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.4version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.2.13version>
dependency>
<dependency>
<groupId>cn.easyprojectgroupId>
<artifactId>orai18nartifactId>
<version>12.1.0.2.0version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.21version>
dependency>
server:
port: 8088
servlet:
context-path: /oraclemybatis
#连接池配置
spring:
datasource:
url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
username: scott
password: tiger
driver-class-name: oracle.jdbc.driver.OracleDriver
#mysql配置如下:
#url: jdbc:mysql://127.0.0.1:3308/mydb?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
#username: root
#password: root2020
#driver-class-name: com.mysql.cj.jdbc.Driver
# 使用druid数据源
#type: com.alibaba.druid.pool.DruidDataSource
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 配置测试查询语句
validationQuery: SELECT 1 FROM DUAL
# 初始化大小,最小,最大
initialSize: 10
minIdle: 10
maxActive: 200
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 180000
testOnBorrow: false
testWhileIdle: true
removeAbandoned: true
removeAbandonedTimeout: 1800
logAbandoned: true
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxOpenPreparedStatements: 100
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall
mybatis:
# 映射文件配置
mapper-locations: classpath:mapper/*.xml
# 实体类的配置,主要改位置
type-aliases-package: com.trkj.mybatisboot.entity
pagehelper:
# 指明这是oracle配置
helperDialect: oracle
reasonable: true
supportMethodsArguments: true
params: count=countS
// config 目录下
package com.trkj.oraclemybatis.config;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
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;
@Configuration /*声明这是一个配置类*/
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource") /*读取前缀是这个的后续东西,构建出Datasource!如果没有这一步就生成的不是我们想要的东西*/
/*不写也可以用,但是不是自己想要的,*/
public DataSource dataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* 配置监控服务器
* @return 返回监控注册的servlet对象
* @author SimpleWu
*/
@Bean
public ServletRegistrationBean statViewServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// 添加IP白名单
servletRegistrationBean.addInitParameter("allow", "127.0.0.1");
// 添加IP黑名单,当白名单和黑名单重复时,黑名单优先级更高
//servletRegistrationBean.addInitParameter("deny", "127.0.0.1");
// 添加控制台管理用户
servletRegistrationBean.addInitParameter("loginUsername", "scott");
servletRegistrationBean.addInitParameter("loginPassword", "tiger");
// 是否能够重置数据
servletRegistrationBean.addInitParameter("resetEnable", "false");
return servletRegistrationBean;
}
/**
* 配置Druid服务过滤器
* @return 返回过滤器配置对象
*/
@Bean
public FilterRegistrationBean statFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
// 添加过滤规则
filterRegistrationBean.addUrlPatterns("/*");
// 忽略过滤格式
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,");
return filterRegistrationBean;
}
}
dao
package com.trkj.oraclemybatis.dao;
import com.trkj.oraclemybatis.entity.Dept;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DeptDao {
int deleteByPrimaryKey(Short deptno);
int insert(Dept record);
int insertSelective(Dept record);
Dept selectByPrimaryKey(Short deptno);
int updateByPrimaryKeySelective(Dept record);
int updateByPrimaryKey(Dept record);
}
entity
package com.trkj.oraclemybatis.entity;
import java.io.Serializable;
import lombok.Data;
/**
* DEPT
* @author
*/
@Data
public class Dept implements Serializable {
private Short deptno;
private String dname;
private String loc;
private static final long serialVersionUID = 1L;
}
service
public interface DeptService {
public Dept findDeptById(Short deptno);
}
@Service
public class DeptServiceImpl implements DeptService {
@Resource
private DeptDao deptDao;
@Override
public Dept findDeptById(Short deptno) {
return deptDao.selectByPrimaryKey(deptno);
}
}
controller
@RestController
@Slf4j
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/dept/{id}")
public Dept selectFindById(@PathVariable("id") Short deptno){
return deptService.findDeptById(deptno);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IwJwdbKW-1638550633747)(SpringBoot.assets/image-20210429162318432.png)]
<properties>
<java.version>1.8java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASEspring-boot.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>com.oracle.database.jdbcgroupId>
<artifactId>ojdbc8artifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>cn.easyprojectgroupId>
<artifactId>orai18nartifactId>
<version>12.1.0.2.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.21version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>jakarta.validationgroupId>
<artifactId>jakarta.validation-apiartifactId>
dependency>
dependencies>
server:
port: 8088
#连接池配置
servlet:
context-path: /jpaboot
spring:
datasource:
url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
username: scott
password: tiger
driver-class-name: oracle.jdbc.driver.OracleDriver
#mysql配置如下:
#url: jdbc:mysql://127.0.0.1:3308/mydb?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
#username: root
#password: root2020
#driver-class-name: com.mysql.cj.jdbc.Driver
# 使用druid数据源
#type: com.alibaba.druid.pool.DruidDataSource
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 配置测试查询语句
validationQuery: SELECT 1 FROM DUAL
# 初始化大小,最小,最大
initialSize: 10
minIdle: 10
maxActive: 200
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 180000
testOnBorrow: false
testWhileIdle: true
removeAbandoned: true
removeAbandonedTimeout: 1800
logAbandoned: true
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxOpenPreparedStatements: 100
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall
jpa:
database: ORACLE
database-platform: org.hibernate.dialect.OracleDialect
show-sql: true
format-sql: true
hibernate:
ddl-auto: update
如果是Mysql则
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQL5Dialect
show-sql: true
hibernate:
ddl-auto: update
定义配置类(见备注,与mybaits时一致)
添加druid StatViewServlet用于展示Druid的统计信息
Spring boot想用使用 其它Servlet或fiter组件的功能,就必须要借用 Spring Boot 提供的 ServletRegistrationBean 接口
配置Druid服务过滤器
访问地址:http://localhost:8088/druid/login.html
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* 配置监控服务器
* @return 返回监控注册的servlet对象
* @author SimpleWu
*/
@Bean
public ServletRegistrationBean statViewServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// 添加IP白名单
servletRegistrationBean.addInitParameter("allow", "127.0.0.1");
// 添加IP黑名单,当白名单和黑名单重复时,黑名单优先级更高
//servletRegistrationBean.addInitParameter("deny", "127.0.0.1");
// 添加控制台管理用户
servletRegistrationBean.addInitParameter("loginUsername", "root");
servletRegistrationBean.addInitParameter("loginPassword", "root2020");
// 是否能够重置数据
servletRegistrationBean.addInitParameter("resetEnable", "false");
return servletRegistrationBean;
}
/**
* 配置Druid服务过滤器
* @return 返回过滤器配置对象
*/
@Bean
public FilterRegistrationBean statFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
// 添加过滤规则
filterRegistrationBean.addUrlPatterns("/*");
// 忽略过滤格式
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,");
return filterRegistrationBean;
}
}
@Slf4j
@Configuration
@EnableTransactionManagement // 开启注解事务管理,等同于xml配置文件中的
@EnableJpaRepositories(
// 实体管理工厂引用名称,对应到@Bean注解对应的方法
entityManagerFactoryRef="entityManagerFactory",
//事务管理工厂引用名称,对应到@Bean注解对应的方法
transactionManagerRef="transactionManager",
basePackages= { "com.trkj.jpaboot.dao" }) //设置Repository所在位置
public class JpaDataConfig {
@Resource
@Qualifier("japDataSource")
private DataSource japDataSource; //primary数据源注入
@Value("${spring.jpa.database-platform}")
private String primaryDialect;
@Value("${spring.jpa.database}")
private String dataBase;
@Value("${spring.jpa.show-sql}")
private String showSql;
@Value("${spring.jpa.hibernate.ddl-auto}")
private String ddlAuto;
@Value("${spring.jpa.format-sql}")
private String formatSql;
@Bean(name = "entityManager") //primary实体管理器
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactory(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactory") //primary实体工厂
public LocalContainerEntityManagerFactoryBean entityManagerFactory (EntityManagerFactoryBuilder builder) {
return builder
.dataSource(japDataSource)
.properties(getVendorProperties())
.packages("com.trkj.jpaboot.entity") //设置实体类所在位置
.persistenceUnit("primaryPersistenceUnit")
.build();
}
@Autowired
private HibernateProperties hibernateProperties;
@Autowired
private JpaProperties jpaProperties;
private Map getVendorProperties() {
jpaProperties.getProperties().put("hibernate.show_sql",showSql);
jpaProperties.getProperties().put("hibernate.format_sql",formatSql);
//jpaProperties.getProperties().put("hibernate.dialect","org.hibernate.dialect.Oracle10gDialect");
jpaProperties.getProperties().put("database-platform",primaryDialect);
jpaProperties.setDatabase(Database.valueOf(dataBase));
hibernateProperties.setDdlAuto(ddlAuto);
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(),new HibernateSettings());
}
@Bean(name = "transactionManager") //事务管理器
public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactory(builder).getObject());
}
}
通过JPA工具生成POJO
@Data
@Validated
public class DeptVo {
@Max(value = 10000,message = "编号不能超过10000")
private long deptno;
@NotEmpty(message = "姓名不能为空")
private String dname;
private String loc;
}
@Entity
@Table(name = "DEPT", schema = "SCOTT", catalog = "")
public class DeptEntity {
private long deptno;
private String dname;
private String loc;
@Id
@Column(name = "DEPTNO")
public long getDeptno() {
return deptno;
}
public void setDeptno(long deptno) {
this.deptno = deptno;
}
@Basic
@Column(name = "DNAME")
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Basic
@Column(name = "LOC")
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DeptEntity that = (DeptEntity) o;
return deptno == that.deptno &&
Objects.equals(dname, that.dname) &&
Objects.equals(loc, that.loc);
}
@Override
public String toString() {
return "DeptEntity{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
'}';
}
@Override
public int hashCode() {
return Objects.hash(deptno, dname, loc);
}
}
定义DAO
import com.trkj.jpaboot.entity.DeptEntity;
import org.springframework.data.repository.CrudRepository;
public interface DeptDao extends CrudRepository<DeptEntity,Integer> {
}
定义Service
public interface DeptService {
public DeptEntity addDeptEntity(DeptEntity dept);
public DeptEntity editDept(DeptEntity dept);
public DeptEntity findDept(DeptEntity dept);
}
@Service
@Slf4j
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
@Transactional(transactionManager = "transactionManager")
public DeptEntity addDeptEntity(DeptEntity dept) {
log.info("addDeptEntity insert data..................");
log.info(dept.toString());
deptDao.save(dept);
log.info("addDeptEntity insert data over..................");
return dept;
}
@Override
@Transactional(transactionManager = "transactionManager")
public DeptEntity editDept(DeptEntity dept) {
return this.deptDao.save(dept);
}
@Override
public DeptEntity findDept(DeptEntity dept) {
long id=dept.getDeptno();
DeptEntity entity=this.deptDao.findById((int)id).orElse(null);
return entity ;
}
}
定义Controller
@RestController
@Slf4j
public class IndexController {
@Autowired
private DeptService deptService;
@PostMapping("/dept")
public AjaxResponse addDept(@RequestBody @Valid DeptVo detpVo){
log.info("开始插入数据。。。");
DeptEntity dept=new DeptEntity();
BeanUtils.copyProperties(detpVo,dept);
deptService.addDeptEntity(dept);
AjaxResponse response=AjaxResponse.success(dept);
return response;
}
@PutMapping("/dept")
public AjaxResponse editDept(@RequestBody @Valid DeptVo detpVo){
log.info("开始修改。。。");
DeptEntity dept=new DeptEntity();
BeanUtils.copyProperties(detpVo,dept);
deptService.editDept(dept);
AjaxResponse response=AjaxResponse.success(dept);
return response;
}
}
@Configuration
@Slf4j
public class AppCorsConfiguration {
private CorsConfiguration buildConfig() {
log.debug("开始设置");
CorsConfiguration appCorsConfiguration = new CorsConfiguration();
appCorsConfiguration.addAllowedOrigin("http://localhost:8082");
appCorsConfiguration.addAllowedOrigin("http://127.0.0.1:8081");
appCorsConfiguration.addAllowedOrigin("http://localhost:8082");
appCorsConfiguration.addAllowedOrigin("http://127.0.0.1:8082");
appCorsConfiguration.addAllowedHeader("*"); // 2允许任何头
appCorsConfiguration.addAllowedMethod("OPTIONS");
appCorsConfiguration.addAllowedMethod("HEAD");
appCorsConfiguration.addAllowedMethod("GET");
appCorsConfiguration.addAllowedMethod("PUT");
appCorsConfiguration.addAllowedMethod("POST");
appCorsConfiguration.addAllowedMethod("DELETE");
appCorsConfiguration.addAllowedMethod("PATCH");
appCorsConfiguration.setAllowCredentials(true);//这两句不加不能跨域上传文件,
appCorsConfiguration.setMaxAge(3600L);//加上去就可
return appCorsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4
return new CorsFilter(source);
}
}
1. > netstat -ano|findstr 8080
2. > >taskkill /pid 15184 /F
//在显示的json格式时,以name显示
@JsonProperty("name")
private String dname;
ss AppCorsConfiguration {
private CorsConfiguration buildConfig() {
log.debug(“开始设置”);
CorsConfiguration appCorsConfiguration = new CorsConfiguration();
appCorsConfiguration.addAllowedOrigin(“http://localhost:8082”);
appCorsConfiguration.addAllowedOrigin(“http://127.0.0.1:8081”);
appCorsConfiguration.addAllowedOrigin(“http://localhost:8082”);
appCorsConfiguration.addAllowedOrigin(“http://127.0.0.1:8082”);
appCorsConfiguration.addAllowedHeader("*"); // 2允许任何头
appCorsConfiguration.addAllowedMethod(“OPTIONS”);
appCorsConfiguration.addAllowedMethod(“HEAD”);
appCorsConfiguration.addAllowedMethod(“GET”);
appCorsConfiguration.addAllowedMethod(“PUT”);
appCorsConfiguration.addAllowedMethod(“POST”);
appCorsConfiguration.addAllowedMethod(“DELETE”);
appCorsConfiguration.addAllowedMethod(“PATCH”);
appCorsConfiguration.setAllowCredentials(true);//这两句不加不能跨域上传文件,
appCorsConfiguration.setMaxAge(3600L);//加上去就可
return appCorsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4
return new CorsFilter(source);
}
}
# 停用端口
```cmake
1. > netstat -ano|findstr 8080
2. > >taskkill /pid 15184 /F
//在显示的json格式时,以name显示
@JsonProperty("name")
private String dname;