首页 文章 精选 留言 我的

精选列表

搜索[springboot],共4370篇文章
优秀的个人博客,低调大师

第十二篇:SpringBoot 2.x数据校验

介绍 在项目的过程中,对于参数的校验是必须的,如果参数比较少的话我们可以直接通过代码进行校验,但是数据较大时再用这个方法就比较笨重了,接下来就该我们的主角Validation闪亮登场了 pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> 实际上在这里数据校验都是调用的javax.validation,spring-boot-starter-web中也包含了hibernate-validator,有兴趣的可以去翻翻文档 User.java package com.priv.gabriel.entity; import lombok.Data; import org.hibernate.validator.constraints.Length; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; /** * Created with Intellij IDEA. * * @Author: Gabriel * @Date: 2018-10-23 * @Description: */ @Data public class User { @NotBlank(message = "name不允许为空") @Length(min = 2,max = 10,message = "你的长度不对劲呀") private String name; @NotNull(message = "进入未成年人入内!") @Min(18) private int age; @NotBlank(message = "拒绝黑户") private String address; } 接下来只需要在Controller层中使用@valid进行校验就可以了 package com.priv.gabriel.controller; import com.priv.gabriel.entity.User; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; /** * Created with Intellij IDEA. * * @Author: Gabriel * @Date: 2018-10-23 * @Description: */ @RestController @RequestMapping("/user") public class UserController { @RequestMapping("/check") public String check(@Valid User user){ return "检测完毕!没有问题"; } } 用Rest Client工具简单检测一下 image.png 结果当然是... { "timestamp": "2018-10-23T09:01:45.159+0000", "status": 400, "error": "Bad Request", "errors": [{ "codes": ["Length.user.name", "Length.name", "Length.java.lang.String", "Length"], "arguments": [{ "codes": ["user.name", "name"], "arguments": null, "defaultMessage": "name", "code": "name" }, 10, 2], "defaultMessage": "你的长度不对劲呀", "objectName": "user", "field": "name", "rejectedValue": "", "bindingFailure": false, "code": "Length" }, { "codes": ["Min.user.age", "Min.age", "Min.int", "Min"], "arguments": [{ "codes": ["user.age", "age"], "arguments": null, "defaultMessage": "age", "code": "age" }, 18], "defaultMessage": "最小不能小于18", "objectName": "user", "field": "age", "rejectedValue": 17, "bindingFailure": false, "code": "Min" }, { "codes": ["NotBlank.user.address", "NotBlank.address", "NotBlank.java.lang.String", "NotBlank"], "arguments": [{ "codes": ["user.address", "address"], "arguments": null, "defaultMessage": "address", "code": "address" }], "defaultMessage": "拒绝黑户", "objectName": "user", "field": "address", "rejectedValue": "", "bindingFailure": false, "code": "NotBlank" }, { "codes": ["NotBlank.user.name", "NotBlank.name", "NotBlank.java.lang.String", "NotBlank"], "arguments": [{ "codes": ["user.name", "name"], "arguments": null, "defaultMessage": "name", "code": "name" }], "defaultMessage": "name不允许为空", "objectName": "user", "field": "name", "rejectedValue": "", "bindingFailure": false, "code": "NotBlank" }], "message": "Validation failed for object='user'. Error count: 4", "path": "/user/check" } 好了,到这里可以看到我们的设置已经生效了,关于数据校验你get到了吗?项目下载地址

优秀的个人博客,低调大师

第五篇:SpringBoot 2.x整合BeetlSQL

image.png 上图是 BeetlSQL官网中对BeetlSQL的介绍,简单来说我们可以得到几个点 开发效率高 维护性好 性能数倍于JPA MyBatis 关于BeetlSQL的更多介绍大家可以去到官网去看看,接下来我们来看看如何把这个DAO工具整合到项目中 pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 引入beetlsql --> <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetlsql</artifactId> <version>2.10.34</version> </dependency> <!-- 引入beetl --> <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> <version>2.9.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> sql文件,我这里用的是mysql CREATE TABLE `test`.`Untitled` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `nickname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `age` int(11) NULL DEFAULT 18, `cdate` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP(0), `udate` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP(0), PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; User.java package com.priv.gabriel.entity; /** * Created with Intellij IDEA. * * @Author: Gabriel * @Date: 2018-10-14 * @Description: */ public class User { private long id; private String username; private String nickname; private int age; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", nickname='" + nickname + '\'' + ", age=" + age + '}'; } } 在这里有两个分支,一种是通过sqlManager来操作,另一种是整合mapper,在这里我们现看看第一种方式 SQLManager方式 UserControllerForSQLManager.java package com.priv.gabriel.controller; import com.priv.gabriel.entity.User; import com.priv.gabriel.repository.UserRepository; import org.beetl.sql.core.SQLManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * Created with Intellij IDEA. * * @Author: Gabriel * @Date: 2018-10-14 * @Description: */ @RestController @RequestMapping("/sqlManager/users") public class UserControllerForSQLManager { //自动注入即可 @Autowired private SQLManager sqlManager; /* * @Author Gabriel * @Description 根据主键查找记录 * @Date 2018/10/16 * @Param [id] 主键 * @Return void */ @RequestMapping(value = "/{id}",method = RequestMethod.GET) public User selectUserById(@PathVariable("id")int id){ //如果没有查到数据则抛出异常 //return sqlManager.unique(User.class,id); //如果没有查到数据则返回null return sqlManager.single(User.class,id); } /* * @Author Gabriel * @Description 查询所有 * @Date 2018/10/16 * @Param [] * @Return java.util.List<com.priv.gabriel.entity.User>*/ @RequestMapping(value = {"","/"},method = RequestMethod.GET) public List<User> getUsers(){ //获取所有数据 //return sqlManager.all(User.class); //查询该表的总数 //return sqlManager.allCount(User.class); //获取所有数据 分页方式 return sqlManager.all(User.class,1,2); } /* * @Author Gabriel * @Description 单表条件查询 * @Date 2018/10/16 * @Param [] * @Return void*/ public void singletonTableQuery(){ //通过sqlManager.query()可以在后面追加各种条件 sqlManager.query(User.class).andLike("username","admin").orderBy("age").select(); } /* * @Author Gabriel * @Description 新增数据 * @Date 2018/10/16 * @Param [user] * @Return void*/ @RequestMapping(value = {"","/"},method = RequestMethod.POST) public void addUser(User user){ //添加数据到对应表中 //sqlManager.insert(User.class,user); //添加数据到对应表中,并返回自增id sqlManager.insertTemplate(user,true); System.out.println(user.getId()); System.out.println("新增成功"); } /* * @Author Gabriel * @Description 根据主键修改 * @Date 2018/10/16 * @Param [user] * @Return java.lang.String*/ @RequestMapping(value = {"","/"},method = RequestMethod.PUT) public String updateById(User user){ //根据id修改,所有值都参与更新 //sqlManager.updateById(user); //根据id修改,属性为null的不会更新 if(sqlManager.updateTemplateById(user)>0){ return "修改成功"; }else{ return "修改失败"; } } /* * @Author Gabriel * @Description 删除记录 * @Date 2018/10/16 * @Param [id] * @Return java.lang.String*/ @RequestMapping(value = "/id",method = RequestMethod.DELETE) public String deleteById(@PathVariable("id") int id){ if(sqlManager.deleteById(User.class,id) >0 ){ return "删除成功"; }else{ return "删除失败"; } } } Mapper方式 如果要使用mapper方式,则需要新建一个mapper接口,并继承BaseMapper<T> UserRepository.java package com.priv.gabriel.repository; import com.priv.gabriel.entity.User; import org.beetl.sql.core.mapper.BaseMapper; /** * Created with Intellij IDEA. * * @Author: Gabriel * @Date: 2018-10-14 * @Description: */ public interface UserRepository extends BaseMapper<User>{ } UserControllerForMapper.java package com.priv.gabriel.controller; import com.priv.gabriel.entity.User; import com.priv.gabriel.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * Created with Intellij IDEA. * * @Author: Gabriel * @Date: 2018-10-14 * @Description: */ @RestController @RequestMapping("/mapper/users") public class UserControllerForMapper { @Autowired private UserRepository repository; @RequestMapping(value = {"","/"},method = RequestMethod.POST) public void addUser(User user){ repository.insert(user); } @RequestMapping(value = {"","/"},method = RequestMethod.DELETE) public String deleteUserById(User user){ if(repository.deleteById(user) >0 ){ return "删除成功"; }else{ return "删除失败"; } } @RequestMapping(value = {"","/"},method = RequestMethod.PUT) public String updateUserById(User user){ //repository.updateById(user) if(repository.deleteById(user) > 0){ return "修改成功"; }else{ return "修改失败"; } } @RequestMapping(value = "/{id}",method = RequestMethod.GET) public User selectUserById(@PathVariable("id")int id){ //repository.unique(id); return repository.single(id); } @RequestMapping(value = {"","/"},method = RequestMethod.GET) public List<User> getUsers(){ //repository.all(1,2); //repository.allCount(); return repository.all(); } } 两种方式都介绍完毕了,但是BeetlSQL的重点部分还不在这,BeetlSQL的重点是可以创建一个SQL模板,到这大家可能会想,不就是个xml嘛,mybatis就有呀,不一样的地方就在这了,BeetlSQL的SQL模板是这样的 selectByTest === select * from user where 1=1 怎么样,是不是眼前一亮,很明显 selectByTest 是这条SQL语句的id , ===的作用是代表id和内容的分割,而最后的部分当然就是SQL语句啦 然后简单介绍一下调用SQL模板的方式 SQLManager方式 @RequestMapping(value = "/test",method = RequestMethod.GET) public List<User> getUsersByTest(){ return sqlManager.select("user.selectByTest",User.class); } 在SQLManager的方式中,通过sqlManager.select("模板id",类型)的方式直接调用 Mapper的方式 @SqlResource("user") public interface UserRepository extends BaseMapper<User>{ List<User> selectByTest(); } 在Mapper的方式,需要先建立一个xxx.md的SQL模板文件,通过@SqlResource(模板文件名)这个注解找到模板文件,再在mapper中写入与模板文件中同名的方法,即可在外部调用 注意,BeetlSQL的模板文件位置默认在resource/sql/xxx.md中,好啦,关于BeetlSQL的介绍就到这里。 BeetlSQL的详细介绍Beetl官方文档BeetlSQL官方文档项目点此下载

优秀的个人博客,低调大师

Spring Cloud 2.x系列之springboot集成quartz

java设计模式之观察者模式 一大波视频分享 Mysql代理中间件Atlas安装和配置 在做项目时有时候会有定时器任务的功能,比如某某时间应该做什么,多少秒应该怎么样之类的。定时任务常用的业务场景是进行数据统计。spring支持多种定时任务的实现,今天介绍一下spring定时器和quartz定时器的使用。 一、spring定时器 spring自带支持定时器的任务实现。其可通过简单配置来实现定时任务。主要用到如下两注解: @EnableScheduling:标注启动定时任务 @Scheduled:定义某个定时任务 常用说明: @Scheduled(fixedRate=2000):上一次开始执行时间点后2秒再次执行 @Scheduled(fixedDelay=2000):上一次执行完毕时间点后2秒再次执行 @Scheduled(initialDelay=1000,fixedDelay=2000):第一次延迟1秒执行,然后在上一次执行完毕时间点后2秒再次执行 @Scheduled(cron="** * * * ?"):按cron规则执行 二、quartz定时任务 quzrtz主要理解如下几个概念: Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。 JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。 Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每凌晨1:00执行,周一、周三、周五下午5:00执行等; Calendar:org.quartz.Calendar和java.util.Calendar不同,它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。一个Trigger可以和多个Calendar关联,以便排除或包含某些时间点。假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。 Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。 1、新建项目,对应的pom.xml文件如下 <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.0http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>spring-cloud</groupId> <artifactId>sc-scheduled</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>sc-scheduled</name> <url>http://maven.apache.org</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 集成quartz需要引入 --> <!--quartz相关依赖--> <!-- <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> </dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> </dependencies> </project> 2、新建sprinboot启动类ScheduledApplication.java package sc.schedule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling // 开启spring自带定时任务 publicclass ScheduledApplication { public static void main(String[] args) { SpringApplication.run(ScheduledApplication.class, args); } } 3、Spring定时任务类 packagesc.schedule.spring; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class SpringScheduled { // 每1分钟执行一次 @Scheduled(cron = "0 */1 * ** * ") public void reportCurrentByCron() { System.out.println("Spring Scheduling Tasks: " + dateFormat().format(new Date())); } private SimpleDateFormat dateFormat() { returnnewSimpleDateFormat("HH:mm:ss"); } } 4、Quartz定时任务类 单任务模式: package sc.schedule.quartz; import org.quartz.JobDetail; import org.quartz.Trigger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean; importorg.springframework.scheduling.quartz.SchedulerFactoryBean; @Configuration publicclass QuartzScheduledOne { @Bean public ScheduledJobOne getScheduledJobOne(){ return new ScheduledJobOne(); } /** * 调度工厂 * *@param jobTrigger * 触发器 *@return */ @Bean(name = "scheduler") public SchedulerFactoryBean schedulerFactory(Trigger jobTrigger) { SchedulerFactoryBeanfactoryBean = new SchedulerFactoryBean(); // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job factoryBean.setOverwriteExistingJobs(true); // 延时启动,应用启动1秒后 factoryBean.setStartupDelay(1); // 注册触发器 factoryBean.setTriggers(jobTrigger); return factoryBean; } /** * * 定时触发器 * *@param reptilianJob * 任务 * *@return * */ @Bean(name = "jobTrigger") public CronTriggerFactory BeancronJobTrigger(JobDetail jobDetail) { CronTriggerFactoryBean tigger = newCronTriggerFactoryBean(); tigger.setJobDetail(jobDetail); // cron表达式,每1分钟执行一次 tigger.setCronExpression("0/20 ** * * ?"); tigger.setName("jobTrigger"); return tigger; } /** * 配置任务 * *@param quartzTask * QuartzTask为需要执行的任务 *@return */ @Bean(name = "jobDetail") public MethodInvokingJobDetailFactory BeandetailFactoryBean(ScheduledJobOne quartzTask) { MethodInvokingJobDetailFactoryBeanjobDetail = new MethodInvokingJobDetailFactoryBean(); // 是否并发执行 jobDetail.setConcurrent(false); // 设置任务的名字 jobDetail.setName("jobDetail"); // 设置任务的分组,在多任务的时候使用 jobDetail.setGroup("jobDetailGroup"); // 需要执行的对象 jobDetail.setTargetObject(quartzTask); /* * TODO非常重要 执行QuartzTask类中的需要执行方法 */ jobDetail.setTargetMethod("execute"); return jobDetail; } } 任务模式参考源码 5、对应的类结构说明 6、启动ScheduledApplication类,并验证定时任务是否启动 (1)注释QuartzScheduled类的Configuration注解 启动ScheduledApplication类查看日志: (2)放开QuartzScheduled类的Configuration注解,然后注释QuartzScheduled类的Configuration注解 启动ScheduledApplication类查看日志: 源码: https://gitee.com/hjj520/spring-cloud-2.x/tree/master/sc-scheduled 本文作者:java乐园 本文来自云栖社区合作伙伴“JAVA乐园”,了解相关信息可以关注“JAVA乐园”

优秀的个人博客,低调大师

精通SpringBoot——第九篇:整合Swagger在线文档

开发中最烦的一件事是什么?当你全心全意思考的时候,前端笑眯眯的过来了:“大哥,你没告诉我该传什么参数!”......然后一堆吧啦吧啦扯淡,好了,前端大佬心满意足的走了,你以为事情也就这么结束了。滴滴滴,微信消息来了:“接口怎么不通啊,你是不是代码写的有问题啊?”一顿操作后,登上控制台,日志一看。啊~(我们一起学土拨鼠叫)内心是崩溃的... 参数少了,参数类型不对,格式不对,各种。这时候很想丢个文档给前端:你自己看吧!然而,写文档真的太麻烦了,懒...只好去逛逛论坛,百度谷歌下有没有什么生成在线文档的工具了,结果如你所愿,还真有。今儿个,咱们就来走一波spring boot 整合 swagger 生成在线文档。(呼~~爽,感觉用了这个,就可以不用被前端大佬“骚扰”了)。介绍两种集成swagger的方式,越用越爽。写文档的时候可以用来和基友尬聊了(编程五分钟,扯淡两小时,一天就这么没了...) 第一招 Without Starter 新建项目,pom 文件加上两个swagger必要的依赖。 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency> Swagger的配置文件 @Configuration @EnableSwagger2 public class SwaggerConfig { /** * swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。 * * @return * @Api:修饰整个类,描述Controller的作用 * @ApiOperation:描述一个类的一个方法,或者说一个接口 * @ApiParam:单个参数描述 * @ApiModel:用对象来接收参数 * @ApiProperty:用对象接收参数时,描述对象的一个字段 * @ApiResponse:HTTP响应其中1个描述 * @ApiResponses:HTTP响应整体描述 * @ApiIgnore:使用该注解忽略这个API * @ApiError:发生错误返回的信息 * @ApiImplicitParam:一个请求参数 * @ApiImplicitParams:多个请求参数 */ @Bean public Docket createRestApi() { /**添加head参数start*/ ParameterBuilder tokenPar = new ParameterBuilder(); List<Parameter> pars = new ArrayList<Parameter>(); tokenPar.name("authorization").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); pars.add(tokenPar.build()); //添加head参数end return new Docket(DocumentationType.SWAGGER_2) .groupName("com.developlee.HangZhou.ZheJiang") .select() .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) //有该注解的生成doc .apis(RequestHandlerSelectors.basePackage("com.developlee.swagger")) // 自行修改为自己的包路径 .paths(PathSelectors.any()) .build() .globalOperationParameters(pars) //set Header .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("DevelopLee的Swagger在线文档") .description("嗯哼嗯哼额~~~swagger文档很强!") .termsOfServiceUrl("http://github.com/developlee") .version("1.0") .build(); } } 写个Controller类测试 @RestController public class UserController { @GetMapping("/userInfo") @ApiOperation(notes = "获取用户信息", value = "get user info") public String getUserInfo(){ return "getUserInfo"; } @PostMapping("/addUser") @ApiOperation(notes = "添加用户信息", value = "add user info") @ApiImplicitParam(value = "添加用户", name = "add user", dataType = "java.lang.String", required = true) public String addUser(String str){ return "addUser"; } } 启动项目...访问 localhost:8080/swagger-ui.html(我滴个龟龟,这就好了?)感动到哭,前端大佬们, see you la la~~(事实上我去找他们聊天了,感受下这个文档带给后端开发人员的福利,尤其是惰性开发人员,比如在座的所有人) 第二招 With swagger-spring-boot-starter 这里介绍一个相当牛逼的工具,来自spring4all.com社区开源的swagger-spring-boot-starter。接下来我们就用这个依赖包开发swagger 文档。pom.xml依赖 <dependency> <groupId>com.spring4all</groupId> <artifactId>swagger-spring-boot-starter</artifactId> <version>1.7.1.RELEASE</version> </dependency> @EnableSwagger2Doc开启文档 @SpringBootApplication @EnableSwagger2Doc public class SwaggerStarterApplication { public static void main(String[] args) { SpringApplication.run(SwaggerStarterApplication.class, args); } } 配置示例: swagger.enabled=true swagger.title=spring-boot-starter-swagger swagger.description=Starter for swagger 2.x swagger.version=1.7.1.RELEASE swagger.license=Apache License, Version 2.0 swagger.licenseUrl=https://www.apache.org/licenses/LICENSE-2.0.html swagger.termsOfServiceUrl=https://github.com/dyc87112/spring-boot-starter-swagger swagger.contact.name=developlee swagger.contact.url=http://github.com/developlee swagger.contact.email=developlee@163.com swagger.base-package=com.developlee swagger.base-path=/** swagger.exclude-path=/error, /ops/** swagger.globalOperationParameters[0].name=name one swagger.globalOperationParameters[0].description=some description one swagger.globalOperationParameters[0].modelRef=string swagger.globalOperationParameters[0].parameterType=header swagger.globalOperationParameters[0].required=true swagger.globalOperationParameters[1].name=name two swagger.globalOperationParameters[1].description=some description two swagger.globalOperationParameters[1].modelRef=string swagger.globalOperationParameters[1].parameterType=body swagger.globalOperationParameters[1].required=false // 取消使用默认预定义的响应消息,并使用自定义响应消息 swagger.apply-default-response-messages=false swagger.global-response-message.get[0].code=401 swagger.global-response-message.get[0].message=401get swagger.global-response-message.get[1].code=500 swagger.global-response-message.get[1].message=500get swagger.global-response-message.get[1].modelRef=ERROR swagger.global-response-message.post[0].code=500 swagger.global-response-message.post[0].message=500post swagger.global-response-message.post[0].modelRef=ERROR 配置说明--默认配置 - swagger.enabled=是否启用swagger,默认:true - swagger.title=标题 - swagger.description=描述 - swagger.version=版本 - swagger.license=许可证 - swagger.licenseUrl=许可证URL - swagger.termsOfServiceUrl=服务条款URL - swagger.contact.name=维护人 - swagger.contact.url=维护人URL - swagger.contact.email=维护人email - swagger.base-package=swagger扫描的基础包,默认:全扫描 - swagger.base-path=需要处理的基础URL规则,默认:/** - swagger.exclude-path=需要排除的URL规则,默认:空 - swagger.host=文档的host信息,默认:空 - swagger.globalOperationParameters[0].name=参数名 - swagger.globalOperationParameters[0].description=描述信息 - swagger.globalOperationParameters[0].modelRef=指定参数类型 - swagger.globalOperationParameters[0].parameterType=指定参数存放位置,可选header,query,path,body.form - swagger.globalOperationParameters[0].required=指定参数是否必传,true,false Path设置 management.context-path=/ops swagger.base-path=/** swagger.exclude-path=/ops/**, /error 上面的设置将解析所有除了/ops/开始以及spring boot自带/error请求路径。 其中,exclude-path可以配合management.context-path=/ops设置的spring boot actuator的context-path来排除所有监控端点。 分组配置 - swagger.docket.<name>.title=标题 - swagger.docket.<name>.description=描述 - swagger.docket.<name>.version=版本 - swagger.docket.<name>.license=许可证 - swagger.docket.<name>.licenseUrl=许可证URL - swagger.docket.<name>.termsOfServiceUrl=服务条款URL - swagger.docket.<name>.contact.name=维护人 - swagger.docket.<name>.contact.url=维护人URL - swagger.docket.<name>.contact.email=维护人email - swagger.docket.<name>.base-package=swagger扫描的基础包,默认:全扫描 - swagger.docket.<name>.base-path=需要处理的基础URL规则,默认:/** - swagger.docket.<name>.exclude-path=需要排除的URL规则,默认:空 - swagger.docket.<name>.name=参数名 - swagger.docket.<name>.modelRef=指定参数类型 - swagger.docket.<name>.parameterType=指定参数存放位置,可选header,query,path,body.form - swagger.docket.<name>.required=true=指定参数是否必传,true,false - swagger.docket.<name>.globalOperationParameters[0].name=参数名 - swagger.docket.<name>.globalOperationParameters[0].description=描述信息 - swagger.docket.<name>.globalOperationParameters[0].modelRef=指定参数存放位置,可选header,query,path,body.form - swagger.docket.<name>.globalOperationParameters[0].parameterType=指定参数是否必传,true,false 更多移步至 github.com。 最后,以上示例代码可在我的github.com中找到。我的个人公众号:developlee的潇洒人生。关注了也不一定更新,更新就不得了了。

优秀的个人博客,低调大师

精通SpringBoot——第四篇:Spring事件 Application Event

Spring的事件为Bean与Bean之间的通信提供了支持,当我们系统中某个Spring管理的Bean处理完某件事后,希望让其他Bean收到通知并作出相应的处理,这时可以让其他Bean监听当前这个Bean所发送的事件。 要实现事件的监听,我们要做两件事:1:自定义事件,继承ApplicationEvent接口2:定义事件监听器,实现ApplicationListener3:事件发布类 /** * @TODO // 自定义事件,继承ApplicationEvent接口 * @Author Lensen * @Date 2018/7/22 * @Description */ public class SendMsgEvent extends ApplicationEvent { private static final long serialVersionID = 1L; // 收件人 public String receiver; // 收件内容 public String content; public SendMsgEvent(Object source) { super(source); } public SendMsgEvent(Object source, String receiver, String content) { super(source); this.receiver = receiver; this.content = content; } public void output(){ System.out.println("I had been sand a msg to " + this.receiver); } } /** * @TODO //定义事件监听器,实现ApplicationListener * @Author Lensen * @Date 2018/7/22 * @Description */@Component public class MsgListener implements ApplicationListener<SendMsgEvent> { @Override public void onApplicationEvent(SendMsgEvent sendMsgEvent) { sendMsgEvent.output(); System.out.println(sendMsgEvent.receiver + "received msg : " + sendMsgEvent.content ); } } 事件发布类 @Component public class Publisher { @Autowired ApplicationContext applicationContext; public void publish(Object source, String receiver, String content){ applicationContext.publishEvent(new SendMsgEvent(source, receiver, content)); } } 测试消息:WebConfig.class主要是为了扫描Publisher 和Listener类。里面有两个注解@ComponenScan和@Configuration。 public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebConfig.class); Publisher publisher = applicationContext.getBean(Publisher.class); publisher.publish("Hello,World!","Mr.Lensen", "I Love U"); } 结果: I had been sand a msg to Mr.Lensen Mr.Lensen received msg : I Love U

优秀的个人博客,低调大师

SpringBoot 整合 oauth2(五)实现 jwt 及 扩展

什么是jwt,即 json web token。JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。也是一种token,但是和token有一些不同。 jwt优点: 自包含 防篡改 可自定义扩展 JWT的结构 JWT包含了使用.分割的三部分: Header 头部 Payload 负载 Signature 签名 比如:eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9 三个新东西 什么是自包含? 字符串里包含用户信息。 什么是防篡改? 签名用于验证消息的发送者以及消息是没有经过篡改的。 可扩展是什么意思? 你可以在Payload部分加入自己想加入的json字符串 那我们既然token的实现方式那么优秀,为什么还要有jwt呢,这就需要了解他们的生成机制。 token生成的其实就是一个UUID,和业务没有丝毫的关系,这样带来最大的问题,就是需要人工持久化处理token(像处理分布式下的sessionId一样)。但是jwt就不需要,因为自包含,所以token里有身份验证信息,不需要做后台持久化处理,前端每次请求被保护的资源时请求头里带上该token就可以实现。 好了开始正文。 本文建立在第三节的基础上。这里是顺风车 1. 新增JwtTokenConfig @Configuration public class JwtTokenConfig{ @Bean public TokenStore jwtTokenStore(){ return new JwtTokenStore(jwtAccessTokenConverter()); } /** * token生成处理:指定签名 */ @Bean public JwtAccessTokenConverter jwtAccessTokenConverter(){ JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("internet_plus"); return accessTokenConverter; } } jwtTokenStore方法返回一个TokenStore对象的子对象JwtTokenStore,供给认证服务器取来给授权服务器端点配置器,通俗点就是让MyAuthorizationServerConfig能注入到值。 jwtAccessTokenConverter方法是根据签名生成JwtToken,同样也需要在MyAuthorizationServerConfig类里注入。 修改MyAuthorizationServerConfig 的 configure方法 /** * 认证服务器 * Created by Fant.J. */ @Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private TokenStore tokenStore; @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { super.configure(security); } /** * 客户端配置(给谁发令牌) * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory().withClient(ConsParams.Auth.GET_CLIENT_ID) .secret(ConsParams.Auth.GET_SECRET) //有效时间 2小时 .accessTokenValiditySeconds(ConsParams.Auth.GET_TOKEN_VALIDITY_SECONDS) //密码授权模式和刷新令牌 .authorizedGrantTypes(ConsParams.Auth.GE_TAUTHORIZED_GRANT_TYPES) .scopes(ConsParams.Auth.GE_TSCOPES); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore) .authenticationManager(authenticationManager) .userDetailsService(userDetailsService) .accessTokenConverter(jwtAccessTokenConverter); } } } 和第三节不同的是 endpoints添加了accessTokenConverter属性,它规定了token生成器是jwtAccessTokenConverter,并按照我们设置的签名来生成。 启动项目 给/oauth/token 发送post请求获取token 请求头:Authorization:Basic +clientid:secret 的base64加密字符串 (认证服务器中设置的client信息) 请求参数:username password (用户登陆账号密码) 2. JWT扩展 在前文我们介绍过jwt的可扩展性,一般情况下实现jwt就可以了,但是有一些特殊需求,比如你想在返回的token中附带一些别的信息,这就需要我们对jwt进行扩展。 2.1 修改JwtTokenConfig 新增jwtTokenEnhancer方法 @Configuration public class JwtTokenConfig{ @Bean public TokenStore jwtTokenStore(){ return new JwtTokenStore(jwtAccessTokenConverter()); } /** * token生成处理:指定签名 */ @Bean public JwtAccessTokenConverter jwtAccessTokenConverter(){ JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("internet_plus"); return accessTokenConverter; } @Bean public TokenEnhancer jwtTokenEnhancer(){ return new JwtTokenEnhancer(); } } jwtTokenEnhancer方法 返回一个JwtTokenEnhancer并交给bean工厂。 2.2 增加JwtTokenEnhancer类 /** * Jwt token 扩展 * Created by Fant.J. */ public class JwtTokenEnhancer implements TokenEnhancer { @Override public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) { Map<String,Object> info = new HashMap<>(); info.put("provider","Fant.J"); //设置附加信息 ((DefaultOAuth2AccessToken)oAuth2AccessToken).setAdditionalInformation(info); return oAuth2AccessToken; } } 重写TokenEnhancer的enhance方法,根据需求扩展jwt。 2.3 修改MyAuthorizationServerConfig类 /** * 认证服务器 * Created by Fant.J. */ @Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private TokenStore tokenStore; @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Autowired private TokenEnhancer jwtTokenEnhancer; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { super.configure(security); } /** * 客户端配置(给谁发令牌) * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory().withClient(ConsParams.Auth.GET_CLIENT_ID) .secret(ConsParams.Auth.GET_SECRET) //有效时间 2小时 .accessTokenValiditySeconds(ConsParams.Auth.GET_TOKEN_VALIDITY_SECONDS) //密码授权模式和刷新令牌 .authorizedGrantTypes(ConsParams.Auth.GE_TAUTHORIZED_GRANT_TYPES) .scopes(ConsParams.Auth.GE_TSCOPES); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore) .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); List<TokenEnhancer> enhancerList = new ArrayList<>(); enhancerList.add(jwtTokenEnhancer); enhancerList.add(jwtAccessTokenConverter); enhancerChain.setTokenEnhancers(enhancerList); endpoints .tokenEnhancer(enhancerChain) .accessTokenConverter(jwtAccessTokenConverter); } } endpoints的tokenEnhancer方法需要我们提供一个token增强器链对象TokenEnhancerChain,所以我们需要在链中加入我们重写的TokenEnhancer和jwtAccessTokenConverter,然后放入endpoints。 启动项目 和上文获取token方式相同。 下图红框便是我添加的扩展。 解析jwt,获取扩展信息 如果我们需要获取jwt本来就有的信息,我们直接请求方法中吧Authentication当做参数,就可以获取到jwt原始信息。 如果我们需要获取jwt扩展的信息,即我们自定义添加的信息,我们需要做这几个操作: pom导入依赖 <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency> UserController.java @GetMapping("/me") public ServerResponse getCurrentUser(Authentication user, HttpServletRequest request) throws UnsupportedEncodingException { String s = user.getPrincipal().toString(); String name = user.getName(); String header = request.getHeader("Authorization"); String token = StringUtils.substringAfter(header,"bearer "); Claims body = Jwts.parser().setSigningKey(ConsParams.Auth.GET_SIGNING_KEY.getBytes("UTF-8")) .parseClaimsJws(token).getBody(); String username = (String) body.get("username"); log.info("解析token获取到的username为{}",username); log.info("从Authentication里获取到的username为{}",s); log.info("从Authentication里获取到的username为{}",name); return ServerResponse.createBySuccess(user); } 介绍下我的所有文集: 流行框架 SpringCloudspringbootnginxredis 底层实现原理: Java NIO教程Java reflection 反射详解Java并发学习笔录Java Servlet教程jdbc组件详解Java NIO教程Java语言/版本 研究

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册