<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.31</version> </dependency>
@Target(ElementType.METHOD) //用在方法上 @Retention(RetentionPolicy.RUNTIME) //运行的时候 @Documented //有文档 public @interface SysLogger { String value() default ""; }
@Aspect // 进行切割 @Component //给spring管理 //切的位置 @Pointcut("@annotation(com.forezp.annotation.SysLogger)") //之前进行操作 @Before("loggerPointCut()") //得到 反射的自然 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //得到 放射的方法 Method method = signature.getMethod(); String methodName = signature.getName(); //从注解上,得到 SysLogger SysLogger sysLogger = method.getAnnotation(SysLogger.class); //得到描述 sysLogger.value() //请求的方法名 类的路径 String className = joinPoint.getTarget().getClass().getName();
@Aspect // 进行切割 @Component //给spring管理 public class SysLoggerAspect { @Autowired private LoggerService loggerService; //切的位置 @Pointcut("@annotation(com.forezp.annotation.SysLogger)") public void loggerPointCut() { } //之前进行操作 @Before("loggerPointCut()") public void saveSysLog(JoinPoint joinPoint) { //得到 反射的自然 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //得到 放射的方法 Method method = signature.getMethod(); //创建log SysLog sysLog = new SysLog(); //从注解上,得到 SysLogger SysLogger sysLogger = method.getAnnotation(SysLogger.class); if(sysLogger != null){ //得到:注解上的描述 sysLog.setOperation(sysLogger.value()); } //请求的方法名 类的路径 String className = joinPoint.getTarget().getClass().getName(); String methodName = signature.getName(); //拼接成 完整的方法 sysLog.setMethod(className + "." + methodName + "()"); //请求的参数 Object[] args = joinPoint.getArgs(); String params=""; for(Object o:args){ //对象转成 json,拼接 params+=JSON.toJSONString(o); } //如果 参数不为空 if(!StringUtils.isEmpty(params)) { //设置上参数 sysLog.setParams(params); } //设置IP地址 sysLog.setIp(HttpUtils.getIpAddress()); //用户名 String username = UserUtils.getCurrentPrinciple(); if(!StringUtils.isEmpty(username)) { //设置上用户名 sysLog.setUsername(username); } //日志的创建时间 sysLog.setCreateDate(new Date()); //保存系统日志 loggerService.log(sysLog); } }
@SysLogger("registry")
public class RespDTO<T> implements Serializable{ public int code = 0; public String error = ""; public T data; public static RespDTO onSuc(Object data) { RespDTO resp = new RespDTO(); resp.data = data; return resp; } }
public class CommonException extends RuntimeException { private ErrorCode errorCode; public CommonException(ErrorCode errorCode) { super(errorCode.getMsg()); this.errorCode = errorCode; } public CommonException(ErrorCode errorCode, String msg) { super(msg); this.errorCode = errorCode; } public ErrorCode getErrorCode() public int getCode() public String getMsg() return errorCode.XXX(如:getMsg()) }
public enum ErrorCode { OK(0, ""), FAIL(-1, "操作失败"), RPC_ERROR(-2,"远程调度失败"), USER_NOT_FOUND(1000,"用户不存在"), USER_PASSWORD_ERROR(1001,"密码错误"), GET_TOKEN_FAIL(1002,"获取token失败"), TOKEN_IS_NOT_MATCH_USER(1003,"请使用自己的token进行接口请求"), BLOG_IS_NOT_EXIST(2001,"该博客不存在") ; private int code; private String msg; ErrorCode(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() public String getMsg() //根据 code,获取 到,这个枚举 public static ErrorCode codeOf(int code) { for (ErrorCode state : values()) { if (state.getCode() == code) { return state; } } return null; } }
@ControllerAdvice //想controller 返回 @ResponseBody public class CommonExceptionHandler { @ExceptionHandler(CommonException.class) //切这个异常 public ResponseEntity<RespDTO> handleException(Exception e) { RespDTO resp = new RespDTO(); //强转 CommonException taiChiException = (CommonException) e; resp.code = taiChiException.getCode(); resp.error = e.getMessage(); //返回 return new ResponseEntity(resp, HttpStatus.OK); } }
if(null==jwt){ throw new CommonException(ErrorCode.GET_TOKEN_FAIL); }
<dependencies> <dependency> <groupId>com.forezp</groupId> <artifactId>common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> starter-netflix-eureka-client starter-config starter-web starter-openfeign starter-actuator starter-netflix-hystrix-dashboard starter-netflix-hystrix starter-sleuth starter-zipkin springfox-swagger2 springfox-swagger-ui.0 mysql-connector-java starter-data-jpa <!--security--> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> starter-amqp </dependencies>
@SpringBootApplication @EnableEurekaClient @EnableFeignClients @EnableHystrixDashboard @EnableHystrix
spring: application: name: blog-service cloud: config: uri: http://localhost:8769 fail-fast: true profiles: active: pro # zipkin: # base-url: http://localhost:9411 # # datasource: # driver-class-name: com.mysql.jdbc.Driver # url: jdbc:mysql://localhost:3306/sys_blog?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8 # username: root # password: 123456 # jpa: # hibernate: # ddl-auto: update # show-sql: true # # rabbitmq: # host: localhost # port: 5672 # username: guest # password: guest # publisher-confirms: true # virtual-host: /
@FeignClient(value = "user-service",fallback = UserServiceHystrix.class ) public interface UserServiceClient { @PostMapping(value = "/user/{username}") RespDTO<User> getUser(@RequestHeader(value = "Authorization") String token, @PathVariable("username") String username); }
@Component public class UserServiceHystrix implements UserServiceClient { @Override public RespDTO<User> getUser(String token, String username) { System.out.println(token); System.out.println(username); return null; } }
public interface BlogDao extends JpaRepository<Blog, Long> { List<Blog> findByUsername(String username); }
@Service public class LoggerService { @Autowired private AmqpTemplate rabbitTemplate; public void log(SysLog sysLog){ rabbitTemplate.convertAndSend(RabbitConfig.queueName, JSON.toJSONString(sysLog)); } }
@Service public class BlogService { @Autowired BlogDao blogDao; @Autowired UserServiceClient userServiceClient; //保存 public Blog postBlog(Blog blog) { return blogDao.save(blog); } //查找 public List<Blog> findBlogs(String username) { return blogDao.findByUsername(username); } //根据ID查找 public BlogDetailDTO findBlogDetail(Long id) { //查询 blog Optional<Blog> blogOptional = blogDao.findById(id); Blog blog=null; //if(blogOptional!=null){ 这是错误的代码,永远为true //如果 博客存在,就得到它 //blog=blogOptional.get(); //会报错 //} if(blogOptional.isPresent()){ blog=blogOptional.get(); } if (null == blog) { throw new CommonException(ErrorCode.BLOG_IS_NOT_EXIST); } RespDTO<User> respDTO = userServiceClient.getUser(UserUtils.getCurrentToken(), blog.getUsername()); if (respDTO==null) { throw new CommonException(ErrorCode.RPC_ERROR); } BlogDetailDTO blogDetailDTO = new BlogDetailDTO(); blogDetailDTO.setBlog(blog); blogDetailDTO.setUser(respDTO.data); return blogDetailDTO; } }
public class BlogDetailDTO { //get set private Blog blog; private User user; }
@Entity public class Blog implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String username; @Column private String title; @Column private String suject; }
public class SysLog { private Long id; //用户名 private String username; //用户操作 private String operation; //请求方法 private String method; //请求参数 private String params; //IP地址 private String ip; //创建时间 private Date createDate; }
public class User { private Long id; private String username; private String password; }
@RestController @RequestMapping("/blog") public class BlogController { @Autowired BlogService blogService; @ApiOperation(value = "发布博客", notes = "发布博客") @PreAuthorize("hasRole('USER')") //user权限,发布 @PostMapping("") @SysLogger("postBlog") public RespDTO postBlog(@RequestBody Blog blog){ //字段判读省略 Blog blog1= blogService.postBlog(blog); return RespDTO.onSuc(blog1); } @ApiOperation(value = "根据用户id获取所有的blog", notes = "根据用户id获取所有的blog") @PreAuthorize("hasAuthority('ROLE_USER')") //必须User权限的 另一种写法 @GetMapping("/{username}") @SysLogger("getBlogs") public RespDTO getBlogs(@PathVariable String username){ //字段判读省略 if(UserUtils.isMyself(username)) { List<Blog> blogs = blogService.findBlogs(username); return RespDTO.onSuc(blogs); }else { throw new CommonException(ErrorCode.TOKEN_IS_NOT_MATCH_USER); } } @ApiOperation(value = "获取博文的详细信息", notes = "获取博文的详细信息") @PreAuthorize("hasAuthority('ROLE_USER')") //获得细节 @GetMapping("/{id}/detail") @SysLogger("getBlogDetail") public RespDTO getBlogDetail(@PathVariable Long id){ return RespDTO.onSuc(blogService.findBlogDetail(id)); } }
public class RespDTO<T> implements Serializable{ public int code = 0; public String error = ""; public T data; public static RespDTO onSuc(Object data) { RespDTO resp = new RespDTO(); resp.data = data; return resp; } }
public BlogDetailDTO findBlogDetail(Long id){ BlogDetailDTO blogDetailDTO = new BlogDetailDTO(); blogDetailDTO.setBlog(blog); blogDetailDTO.setUser(respDTO.data); return blogDetailDTO; } public class BlogDetailDTO { private Blog blog; private User user; }
common 自己写的 starter-config starter-actuator starter-netflix-eureka-client starter-web spring-security-jwt spring-security-oauth2 mysql-connector-java starter-data-jpa starter-amqp
spring: application: name: logger-service cloud: config: uri: http://localhost:8769 fail-fast: true profiles: active: pro
@EnableEurekaClient @EnableDiscoveryClient
public interface SysLogDAO extends JpaRepository<SysLog, Long> { }
@Entity public class SysLog implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; //用户名 @Column private String username; //用户操作 @Column private String operation; //请求方法 @Column private String method; //请求参数 @Column private String params; //IP地址 @Column private String ip; //创建时间 @Column private Date createDate; }
//每收到一个消息,就会 走这个方法 @Component public class Receiver { private CountDownLatch latch = new CountDownLatch(1); @Autowired SysLogService sysLogService; public void receiveMessage(String message) { System.out.println("Received <" + message + ">"); //收到的消息,转成 syslog SysLog sysLog= JSON.parseObject(message,SysLog.class); //保存日志 sysLogService.saveLogger(sysLog); latch.countDown(); //释放信号量 } } CountDownLatch 信号量的作用,只有其他的线程 完成了一系列的操作,释放信号后,其他被阻塞的线程 获取到 信号才能被唤醒
@Component public class Sender { @Autowired private AmqpTemplate rabbitTemplate; public void send() { String context = "hello " + new Date(); System.out.println("Sender : " + context); //发送消息 rabbitTemplate.convertAndSend(RabbitConfig.queueName, "Hello from RabbitMQ!"); } }
public class User { private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; }
@Service public class SysLogService { @Autowired SysLogDAO sysLogDAO; public void saveLogger(SysLog sysLog){ sysLogDAO.save(sysLog); } }
@Configuration public class RabbitConfig { public final static String queueName = "spring-boot"; @Bean Queue queue() { return new Queue(queueName, false); } @Bean TopicExchange exchange() { return new TopicExchange("spring-boot-exchange"); } @Bean Binding binding(Queue queue, TopicExchange exchange) { return BindingBuilder.bind(queue).to(exchange).with(queueName); } @Bean SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames(queueName); container.setMessageListener(listenerAdapter); return container; } @Bean //把receiveMessage类,传递到 消息监听者 中 MessageListenerAdapter listenerAdapter(Receiver receiver) { return new MessageListenerAdapter(receiver, "receiveMessage"); } }
CREATE DATABASE `sys-blog` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; use `sys-blog`; SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for blog -- ---------------------------- DROP TABLE IF EXISTS `blog`; CREATE TABLE `blog` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `suject` varchar(255) DEFAULT NULL, `title` varchar(255) DEFAULT NULL, `username` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; INSERT INTO `blog` VALUES ('5', '今天天气真好', '一起出去玩啊', 'fzp');
CREATE DATABASE `sys-log` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; use `sys-log`; SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for sys_log -- ---------------------------- DROP TABLE IF EXISTS `sys_log`; CREATE TABLE `sys_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `create_date` datetime DEFAULT NULL, `ip` varchar(255) DEFAULT NULL, `method` varchar(255) DEFAULT NULL, `operation` varchar(255) DEFAULT NULL, `params` varchar(255) DEFAULT NULL, `username` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=267 DEFAULT CHARSET=utf8;
CREATE DATABASE `sys-user` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; use `sys-user`; -- ---------------------------- -- Table structure for role -- ---------------------------- DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `password` varchar(255) DEFAULT NULL, `username` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UK_sb8bbouer5wak8vyiiy4pf2bx` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for user_role -- ---------------------------- DROP TABLE IF EXISTS `user_role`; CREATE TABLE `user_role` ( `user_id` bigint(20) NOT NULL, `role_id` bigint(20) NOT NULL, KEY `FKa68196081fvovjhkek5m97n3y` (`role_id`), KEY `FK859n2jvi8ivhui0rl0esws6o` (`user_id`), CONSTRAINT `FK859n2jvi8ivhui0rl0esws6o` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`), CONSTRAINT `FKa68196081fvovjhkek5m97n3y` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `user` VALUES ('1', '$2a$10$rlM./Q4dh5qXYmxFxUqkRetMPf6JewV/Hj/s4qBg/6U1.mzcue2oK', 'fzp'); INSERT INTO `role` VALUES ('1', 'ROLE_USER'); INSERT INTO `role` VALUES ('2', 'ROLE_ADMIN'); INSERT INTO `user_role` VALUES ('1', '1'); INSERT INTO `user_role` VALUES ('1', '2');
http://localhost:5000/userapi/user/registry post json请求 { "password":"123456", "username":"miya2" } 返回: { "id": 15, "username": "miya2", "password": "$2a$10$I/mvNH15Axgv/M6e6ml8WuFt2kEjzY4K9PXNlFfDr.50FSq563Aca" }
http://localhost:5000/userapi/user/login post请求, form-data请求,加两个参数: username miya2 password 123456 返回: { "code": 0, "error": "", "data": { "user": { "id": 15, "username": "miya2", "password": "$2a$10$I/mvNH15Axgv/M6e6ml8WuFt2kEjzY4K9PXNlFfDr.50FSq563Aca" }, "token": "eyJhbGciOiJSU9YQ4bKw" } }
post http://localhost:5000/userapi/user/miya hearder Authorization 值为:Bearer eyJhbGcixxxtoken { "error": "access_denied", "error_description": "不允许访问" }
{ "code": 0, "error": "", "data": { "id": 13, "username": "miya", "password": "$2a$10$FM3gA3uFuYwDXH8BIfKm9egtWQRTDyM4z885rY5UMXnflcVVgbYie" } }
http://localhost:5000/blogapi/blog post请求: Authorization 注意header { "id":"20", "username":"miya", "title":"标题1", "suject":"主题1" }
返回这样的内容: { "code": 0, "error": "", "data": { "id": 6, "username": "miya", "title": "标题1", "suject": "主题1" } }
http://localhost:5000/blogapi/blog/6/detail 获得博客。 上面的ID没用 { "code": 0, "error": "", "data": { "blog": { "id": 6, "username": "miya", "title": "标题1", "suject": "主题1" }, "user": { "id": 13, "username": "miya", "password": "$2a$10$FM3gA3uFuYwDXH8BIfKm9egtWQRTDyM4z885rY5UMXnflcVVgbYie" } }
1. Queue springCloudBus.anonymous.Z8qPhVppRkuH0RA-v0jCXg 启动后,mq服务器上 有此队列,绑定到:springCloudBus 2. 访问:http://localhost:8769/uaa-service-pro.yml,即可得到此项目配置 访问:http://localhost:8769/admin-service-pro.yml 有一个默认 8761的 eureka配置,不知原因。共两个eureka配置 service-url: defaultZone: http://localhost:8761/eureka/ 3. 阿波罗会在本地这样的缓存,C:\opt\data\account-system\config-cache 。cloud config好像没有
http://localhost:8769/actuator/jolokia
http://localhost:8769/actuator
{ "request": { "type": "version" }, "value": { "agent": "1.6.0", "protocol": "7.2", "config": { "listenForHttpService": "true", "authIgnoreCerts": "false", "agentId": "192.168.44.1-14152-4def42c3-servlet", "debug": "false", "agentType": "servlet", "policyLocation": "classpath:/jolokia-access.xml", }, "info": { "product": "tomcat", "vendor": "Apache", "version": "9.0.12" } }, "timestamp": 1629773086, "status": 200 }
zk也是注册到 eureka 上的。哎,不能用。
admin-server:9998 blog-service:8763 gateway-service:5000 logger-service:9997 monitor-service:8766 uaa-service:9999 user-service:8762 zipkin-server:9411 共计11个项目,配置中心,和 common 和 eureka 不算。还有8个。 另外 zipkin server需要 自己建立 user blog log都配置了 Mq,队列:spring-boot 交换器:spring-boot-exchange 。加上 配置中心,mq一共4个客户端。
登录admin server:http://localhost:9998/#/applications 输入用户名密码:admin 看 web下 mappings, 可以看到所有的 请求路径 mappings
1. 访问:monitor-service 的 dashboard: http://localhost:8766/hystrix 2. turbine.stream访问: 在dashboard填入:http://localhost:8766/turbine.stream 看配置 自动聚合了:blog-service,user-service 的 hystrix http://localhost:8766/actuator/hystrix.stream 监控项目的hystrix无用的。 3. 访问下面的接口后:,dashboard里面将会有内容: http://localhost:5000/userapi/user/miya http://localhost:5000/blogapi/blog/miya2 (重要的是下面登录接口) http://localhost:5000/blogapi/blog/6/detail 会访问:/user-service/user/{username} http://localhost:5000/userapi/user/login?username=miya2&password=123456 //会访问:/uaa-service/oauth/token 访问成功后,即可看到 dashboard