(二期)11、开源博客项目mblog解读(一)
- http://www.cnblogs.com/fangjian0423/p/springMVC-request-mapping.html
- 一种是直接实现自己的HandlerExceptionResolver
- 一种是使用注解
- 1 @ControllerAdvice+@ExceptionHandler:配置对全局异常进行处理
- 2 @Controller + @ExceptionHandler:配置对当前所在Controller的异常进行处理
- 返回 modelAndView
- 返回一个页面的地址
- 返回 JSON
- 返回 http 错误码
- ExceptionHandlerExceptionResolver: 根据@ExceptionHandler注解的方法处理对应的异常。其实上文的通过注解的方式处理异常,实际就是在这个类中实现
- ResponseStatusExceptionResolver: 根据@ResponseStatus注解的方法处理异常
- DefaultHandlerExceptionResolver: 将异常转化为特定的HTTP的状态码
- HandlerExceptionResolverComposite:此类通过列表包含以上3个HandlerExceptionResolver,当捕获异常时,会循环调用以上3个HandlerExceptionResolver进行处理
ExceptionHandlerExceptionResolver处理过程总结一下:
- 根据用户调用Controller中相应的方法得到HandlerMethod,之后构造ExceptionHandlerMethodResolver,
- 构造ExceptionHandlerMethodResolver有2种选择,
- 1.通过HandlerMethod拿到Controller,找出Controller中带有@ExceptionHandler注解的方法(局部)
- 2.找到@ControllerAdvice注解配置的类中的@ExceptionHandler注解的方法(全局)。
- 这2种方式构造的ExceptionHandlerMethodResolver中都有1个key为Throwable,value为Method的缓存。之后通过发生的异常找出对应的Method,然后调用这个方法进行处理。
- 这里异常还有个优先级的问题,比如发生的是NullPointerException,但是声明的异常有Throwable和Exception,这时候ExceptionHandlerMethodResolver找Method的时候会根据异常的最近继承关系找到继承深度最浅的那个异常,即Exception。
Spring的事件遵循的流程
逻辑整理
- 定义通知事件NotifyEvent。
- FollowController.sendNotify()-->发送关注通知。
- NotifyEventHandler,关注事件监听处理类,保存通知到数据库
- https://blog.csdn.net/chszs/article/details/49097919
有条件的事件处理
定义事件
public class TestEvent extends ApplicationEvent {
public boolean isImport;
public TestEvent(Object source, boolean isImport) {
super(source);
this.isImport = isImport;
}
public boolean isImport() {
return isImport;
}
public void setImport(boolean anImport) {
isImport = anImport;
}
@Override
public String toString() {
return "TestEvent{" +
"isImport=" + isImport +
'}';
}
}
定义监听
@Component
public class EventHandler {
@EventListener(condition="#testEvent.isImport")
public void TestEventTest(TestEvent testEvent) {
System.out.println("==============TestEvent==============" + testEvent.toString());
}
}
public class GuavaEvent {
private final int message;
public GuavaEvent(int message) {
this.message = message;
System.out.println("event message:"+message);
}
public int getMessage() {
return message;
}
}
public class GuavaEventListener {
public int lastMessage = 0;
@Subscribe
public void listen(GuavaEvent event) {
lastMessage = event.getMessage();
System.out.println("guava--------Message:"+lastMessage);
}
public int getLastMessage() {
return lastMessage;
}
}
//guava test
EventBus eventBus = new EventBus();
GuavaEventListener listener = new GuavaEventListener();
eventBus.register(listener);
eventBus.post(new GuavaEvent(200));
eventBus.post(new GuavaEvent(300));
System.out.println("LastMessage:"+listener.getLastMessage());
监听特定事件(如,CustomerChangeEvent)
- 传统实现:定义相应的事件监听者类,如CustomerChangeEventListener;
- EventBus实现:以CustomerChangeEvent为唯一参数创建方法,并用Subscribe注解标记。
把事件监听者注册到事件生产者:
- 传统实现:调用事件生产者的registerCustomerChangeEventListener方法;这些方法很少定义在公共接口中,因此开发者必须知道所有事件生产者的类型,才能正确地注册监听者;
- EventBus实现:在EventBus实例上调用EventBus.register(Object)方法;请保证事件生产者和监听者共享相同的EventBus实例。
按事件超类监听(如,EventObject甚至Object):
- 传统实现:很困难,需要开发者自己去实现匹配逻辑;
- EventBus实现:EventBus自动把事件分发给事件超类的监听者,并且允许监听者声明监听接口类型和泛型的通配符类型(wildcard,如 ? super XXX)。
检测没有监听者的事件:
- 传统实现:在每个事件分发方法中添加逻辑代码(也可能适用AOP);
- EventBus实现:监听DeadEvent;EventBus会把所有发布后没有监听者处理的事件包装为DeadEvent(对调试很便利)。
事件生产者[Producers]
管理和追踪监听者:
- 传统实现:用列表管理监听者,还要考虑线程同步;或者使用工具类,如EventListenerList;
- EventBus实现:EventBus内部已经实现了监听者管理。
向监听者分发事件:
- 传统实现:开发者自己写代码,包括事件类型匹配、异常处理、异步分发;
- EventBus实现:把事件传递给 EventBus.post(Object)方法。异步分发可以直接用EventBus的子类AsyncEventBus。
@PostContruct
从这个文件开始看:
- UploadController
- 图片上传的入口,通过upload方法上传图片,并返回上传结果
- FileRepo
- 图片上传接口,定义图片上传应该拥有的所有相关方法
- AbstractFileRepo
- 实现FileRepo接口,把实现类基础公用部分的方法实现。
- FileRepoImpl
- 继承抽象类AbstractFileRepo,重写getRoot()方法,为绝对路径保存图片
DateFormatUtils.format(new Date(), YYYYMMDDHHMMSS);
//输出值格式例如:/2018/0527/27160051
- 指定大小进行缩放
- 按照比例进行缩放
- 不按照比例,指定大小进行缩放
- 旋转
- 水印
- 裁剪
- 转化图像格式
- 输出到OutputStream
- 输出到BufferedImage
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
- https://blog.csdn.net/qq_25508039/article/details/82257436
传统授权方式缺点:
- https://www.jianshu.com/p/d74ce6ca0c33
OAuth的校验流程为什么这么复杂,直接授权之后redirect回accessToken不就结了吗?为什么还要返回auth_code之后请求accessToken?
- 对client_id和回调地址做严格校验
- 获取access token的code仅能使用一次,且与授权用户关联
- 尽量避免直接读取当前用户session进行绑定
- 有效使用client_secret参数
- 使用Authorization Code方式进行授权
- 授权过程使用state随机哈希,并在服务端进行判断
- 尽量使用HTTPS保证授权过程的安全性
- 最后,对oauth2.0有详细的了解,严格按照流程进行开发。
QQ登录OAuth2.0总体处理流程如下:
Step1
Step2
Step3
Step4
Step5
Step6
- QQ登录按钮链接
- http://localhost:8080/oauth/callback/call_qq
- 获取Authorization Code
- https://graph.qq.com/oauth2.0/authorize?response_type=code&redirect_uri=&state=0vnuc37nwskcs9cr3yo1wvaq&client_id=
- 通过Authorization Code获取Access Token
- grant_type=&authorization_code&redirect_uri=
- 通过accessToken获取openid
- access_token=
- 通过accessToken和openid获取用户信息
- https://graph.qq.com/user/get_user_info?access_token=&oauth_consumer_key=&openid=&format=json
- 判断是否已经注册,为注册跳转到/bind_oauth方法进行账号注册与绑定。然后使用shiro登录。