- 1、异常处理
- 2、 异步请求
- 3、发送邮件
- 4、跨域
- 5、获取文件
- 6、远程调试
- -agentlib:jdwp=transport=dt_socket,server=y,address=8000
- -agentlib:jdwp=transport=dt_socket,server=y,address=localhost:8000,timeout=5000
- -agentlib:jdwp=transport=dt_shmem,server=y,suspend=n
- -agentlib:jdwp=transport=dt_socket,address=myhost:8000
- -agentlib:jdwp=transport=dt_socket,server=y,address=8000,onthrow=java.io.IOException,launch=/usr/local/bin/debugstub
- 7、静态资源服务
- 8、Mybatis plus LocalTime
- 9、AOP
1、异常处理
1.1 全局异常
@Slf4j@ControllerAdvicepublic class GlobalExceptionHandler {@ExceptionHandler(value = Exception.class)@ResponseBodypublic String XXXExceptionHandler(Exception e) {log.info(e.toString());return "123";}}
1.2 自定义异常
// 异常直接抛给 tomcat, 如果后续处理异常,则显示错误页面throw new CustomExceptionHandler("错误");@NoArgsConstructor@ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "拒绝访问") // 403public class CustomExceptionHandler extends RuntimeException{public CustomExceptionHandler(String message){super(message);}}
@Order(value = Ordered.HIGHEST_PRECEDENCE) // 最高级别,处理所有异常(其他任何异常配置失效)@Componentpublic class CustomerHandlerException implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object handler, Exception e) {try {httpServletResponse.sendError(555,"wuwuwu异常"); // 抛给 tomcat} catch (IOException ioException) {ioException.printStackTrace();}return new ModelAndView();}}
2、 异步请求
启动类: @EnableAsync
@GetMapping("/callable")private Callable<Object> getCallable(){log.info(Thread.currentThread().getName() + " 进入 getCallable 方法");Callable<Object> callable = new Callable<Object>() {@Overridepublic Object call() throws Exception {log.info(Thread.currentThread().getName() + " 进入 call 方法");Object say = sayHello();log.info(Thread.currentThread().getName() + " 从 Service 方法返回");return say;}};log.info(Thread.currentThread().getName() + " 从 getCallable 方法返回");return callable;}@GetMapping("/webAsyncTask")private WebAsyncTask<Object> getWebAsyncTask(){log.info(Thread.currentThread().getName() + " 进入 getWebAsyncTask 方法");// 3s 没返回,则认为超时WebAsyncTask<Object> webAsyncTask = new WebAsyncTask<>(3000, new Callable<Object>() {@Overridepublic Object call() throws Exception {log.info(Thread.currentThread().getName() + " 进入call方法");Object say = sayHello();log.info(Thread.currentThread().getName() + " 从 Service 方法返回");return say;}});log.info(Thread.currentThread().getName() + " 从 Service 方法返回");webAsyncTask.onCompletion(new Runnable() {@Overridepublic void run() {log.info(Thread.currentThread().getName() + " 执行完毕");}});webAsyncTask.onTimeout(new Callable<Object>() {@Overridepublic Object call() throws Exception {log.info(Thread.currentThread().getName() + " onTimeout");// 超时的时候,直接抛异常,让外层统一处理超时异常throw new TimeoutException("调用超时");}});return webAsyncTask;}@GetMapping("/deferredResult")private DeferredResult<Object> getDeferredResult(){log.info(Thread.currentThread().getName() + " 进入 getDeferredResult 方法");DeferredResult<Object> deferredResult = new DeferredResult<>(3000L);// 调用长时间执行任务execute(deferredResult);// 当长时间任务中使用deferred.setResult("world");这个方法时,会从长时间任务中返回,继续controller里面的流程log.info(Thread.currentThread().getName() + "从 execute 方法返回");// 超时的回调方法deferredResult.onTimeout(new Runnable(){@Overridepublic void run() {log.info(Thread.currentThread().getName() + " onTimeout");// 返回超时信息deferredResult.setErrorResult("time out!");}});// 处理完成的回调方法,无论是超时还是处理成功,都会进入这个回调方法deferredResult.onCompletion(new Runnable(){@Overridepublic void run() {log.info(Thread.currentThread().getName() + " onCompletion");}});return deferredResult;}@Asyncpublic void execute(DeferredResult<Object> deferredResult) {log.info(Thread.currentThread().getName() + "进入 execute 方法");try {// 模拟长时间任务调用,睡眠 2sTimeUnit.SECONDS.sleep(5);// 2s 后给 Deferred 发送成功消息,告诉 Deferred ,我这边已经处理完了,可以返回给客户端了deferredResult.setResult("world");} catch (InterruptedException e) {e.printStackTrace();}}private Object sayHello() {try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}Map<String,Object> map = new HashMap<>();map.put("a",1);map.put("b",2);return map;}
3、发送邮件
Pom
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>
yaml
spring:# 126邮箱SMTP服务器地址:smtp.126.com,端口号:465或者994# 2163邮箱SMTP服务器地址:smtp.163.com,端口号:465或者994# yeah邮箱SMTP服务器地址:smtp.yeah.net,端口号:465或者994# qq邮箱SMTP服务器地址:smtp.qq.com,端口号465或587*mail:default-encoding: UTF-8host: smtp.qq.comusername: 953598751@qq.compassword: xxxport: 587properties:mail:stmp:socketFactoryClass: javax.net.ssl.SSLSocketFactory#表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误debug: true
Test
@Autowiredprivate JavaMailSender javaMailSender;private final ClassPathResource classPathResource = new ClassPathResource("static/test.jpg");@Testpublic void sendString(){// 构建一个邮件对象SimpleMailMessage message = new SimpleMailMessage();// 设置邮件主题message.setSubject("这是一封测试邮件");// 设置邮件发送者,这个跟 application.yml中设置的要一致message.setFrom("953598751@qq.com");// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似message.setTo("1349587649@qq.com");// 设置邮件抄送人,可以有多个抄送人。// 将邮件同时送给收信人以外的人,用户所写的邮件抄送一份给别人,对方可以看见该用户的E-mail发送给了谁。// message.setCc("idu8972@dingtalk.com");// 设置隐秘抄送人,可以有多个。// 将邮件同时送给收信人以外的人,用户所写的邮件抄送一份给别人,但是对方不能查看到这封邮件同时还发送给了哪些人。// message.setBcc("idu8972@dingtalk.com");// 设置邮件发送日期message.setSentDate(new Date());// 设置邮件的正文message.setText("这是测试邮件的正文");// 发送邮件javaMailSender.send(message);}/*** 发送带附件的邮件*/@Testpublic void sendAttachFileMail() throws MessagingException, IOException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();// true表示构建一个可以带附件的邮件对象MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);helper.setSubject("这是一封测试邮件");helper.setFrom("953598751@qq.com");helper.setTo("1349587649@qq.com");helper.setSentDate(new Date());helper.setText("这是测试邮件的正文");// 第一个参数是自定义的名称,后缀需要加上,第二个参数是文件的位置helper.addAttachment("报表.pdf",classPathResource.getFile());javaMailSender.send(mimeMessage);}/*** 正文中带图片的邮件*/@Testpublic void sendImgResMail() throws MessagingException, IOException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);helper.setSubject("这是一封测试邮件");helper.setFrom("953598751@qq.com");helper.setTo("1349587649@qq.com");helper.setSentDate(new Date());// src='cid:p01' 占位符写法 ,第二个参数true表示这是一个html文本helper.setText("<H1>hello 大家好,这是一封测试邮件,这封邮件包含两种图片,分别如下</H1>" +"<H3>第一张图片:</H3><img src='cid:img01'/>",true);// 第一个参数指的是 html 中占位符的名字,第二个参数就是文件的位置helper.addInline("img01",new FileSystemResource(classPathResource.getFile()));helper.addAttachment("test.jpg",classPathResource.getFile());javaMailSender.send(mimeMessage);}
4、跨域
@Configuration@EnableWebMvc // 使用 swagger 不能有该注解public class WebConfig extends WebMvcConfigurerAdapter {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET","POST").allowCredentials(false).maxAge(3600);}}@Configurationclass CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {//添加映射路径registry.addMapping("/**")//是否发送Cookie.allowCredentials(true)//设置放行哪些原始域 SpringBoot2.4.4下低版本使用.allowedOrigins("*").allowedOriginPatterns("*")//放行哪些请求方式.allowedMethods("GET", "POST")//.allowedMethods("*") //或者放行全部//放行哪些原始请求头部信息.allowedHeaders("*")//暴露哪些原始请求头部信息.exposedHeaders("*");}/** swagger 访问 **/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");WebMvcConfigurer.super.addResourceHandlers(registry);}}public class MyCorsFilter extends CorsFilter {public MyCorsFilter() {super(configurationSource());}private static UrlBasedCorsConfigurationSource configurationSource() {CorsConfiguration config = new CorsConfiguration();config.setAllowCredentials(true);config.addAllowedOrigin("http://domain1.com");config.addAllowedHeader("*");config.addAllowedMethod("GET","POST");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config);return source;}}// 注解形式@CrossOrigin(origins = "*",maxAge = 3600)
5、获取文件
// 获取 classpath 路径下的文件ClassPathResource classPathResource = new ClassPathResource("static/index.html");File file = classPathResource.getFile();System.out.println(file.getName());// 获取项目路径下的文件FileSystemResource fileSystemResource = new FileSystemResource("pom.xml");File file1 = fileSystemResource.getFile();FileReader fileReader = new FileReader(file1);char[] chars = new char[100];if(fileReader.read(chars)!=-1){System.out.println(String.valueOf(chars));}
6、远程调试
- 启动命令: java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 -jar web.jar
-agentlib:jdwp=transport=dt_socket,server=y,address=8000
以 Socket 方式监听 8000 端口,程序启动阻塞(suspend 的默认值为y)直到被连接。
-agentlib:jdwp=transport=dt_socket,server=y,address=localhost:8000,timeout=5000
以 Socket 方式监听 8000 端口,当程序启动后5秒无调试者连接的话终止,程序启动阻塞(suspend的默认值为y)直到被连接。
-agentlib:jdwp=transport=dt_shmem,server=y,suspend=n
选择可用的共享内存连接地址并使用 stdout 打印,程序启动不阻塞。
-agentlib:jdwp=transport=dt_socket,address=myhost:8000
以 socket 方式连接到 myhost:8000上的调试程序,在连接成功前启动阻塞。
-agentlib:jdwp=transport=dt_socket,server=y,address=8000,onthrow=java.io.IOException,launch=/usr/local/bin/debugstub
以 Socket 方式监听 8000 端口,程序启动阻塞(suspend的默认值为y)直到被连接。当抛出
IOException时中断调试,转而执行usr/local/bin/debugstub程序。
- 参数说明
| transport | 指定运行的被调试应用和调试者之间的通信协议,它由几个可选值: |
| —- | —- |
| |
dt_socket
:主要的方式,采用 socket 方式连接 | | server | 当前应用作为调试服务端还是客户端,默认为n
。
如果你想将当前应用作为被调试应用,设置该值为y
;如果你想将当前应用作为客户端,作为调试的发起者,设置该值为n| | suspend | 当前应用启动后,是否阻塞应用直到被连接,默认值为y
。
在大部分的应用场景,这个值为n
,即不需要应用阻塞等待连接。
一个可能为y
的应用场景是,你的程序在启动时出现了一个故障,为了调试,必须等到调试方连接上来后程序再启动 | | address | 暴露的调试连接端口,默认值为8000| | onthrow | 当程序抛出设定异常时,中断调试 | | onuncaught | 当程序抛出未捕获异常时,是否中断调试,默认值为n| | launch | 当调试中断时,执行的程序。 | | timeout | 该参数限定为java -agentlib:jdwp=…
可用,单位为毫秒ms。
当 suspend = y 时,该值表示等待连接的超时;当 suspend = n 时,该值表示连接后的使用超时。 |
- IDEA 调试
Edit Configurations
>添加一个 Remote JVM Debug>配置 Host 和 Port>启动该配置
7、静态资源服务
@Configurationclass CorsConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/img/**").addResourceLocations("file:D:/app_3d/fpt/");registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");WebMvcConfigurer.super.addResourceHandlers(registry);}}
8、Mybatis plus LocalTime
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime updateTime;@Bean(name = "mapperObject")public ObjectMapper getObjectMapper() {JavaTimeModule javaTimeModule = new JavaTimeModule();javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));return new ObjectMapper().registerModule(javaTimeModule);}
9、AOP
<!-- <dependency>--><!-- <groupId>org.aspectj</groupId>--><!-- <artifactId>aspectjweaver</artifactId>--><!-- <version>1.8.13</version>--><!-- </dependency>--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
@Componentpublic class User {public void add(String str){System.out.println("add..........." + str);}}@Component@Aspect@Order(1) // 设置增强顺序public class UserProxy1 {/*** 前置通知*/@Before(value = "execution(* com.cug.aop.User.add(..))")public void before(){System.out.println("UserProxy1 before...........");}}/*** @Description 创建不同的方法,代表不同的通知类型*/@Aspect@Component@Order(2) // 设置增强顺序public class UserProxy {/*** 相同切入点抽取*/@Pointcut(value = "execution(* com.cug.aop.User.add(..))")public void pointDemo(){}/*** 前置通知*/@Before(value = "pointDemo()")public void before(JoinPoint joinPoint){System.out.println(Arrays.toString(joinPoint.getArgs()));// 2System.out.println("before...........");}@After(value = "execution(* com.cug.aop.User.add(..))")public void after(){// 4System.out.println("after..........");}@AfterReturning(value = "execution(* com.cug.aop.User.add(..))")public void afterReturning(){// 3 增强的方法之后System.out.println("AfterReturning..........");}@AfterThrowing(value = "execution(* com.cug.aop.User.add(..))")public void afterThrowing(){System.out.println("AfterThrowing..........");}@Around(value = "execution(* com.cug.aop.User.add(..))")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {// 1System.out.println("Around before..........");// 被增强的方法执行proceedingJoinPoint.proceed();// 5System.out.println("Around after..........");return "around";}}@SpringBootTestclass ApoApplicationTests {@Autowiredprivate User user;@Testvoid contextLoads() {user.add("111");}}
