微服务全部知识点总结

编程入门 行业动态 更新时间:2024-10-08 13:30:36

微服务全部<a href=https://www.elefans.com/category/jswz/34/1770093.html style=知识点总结"/>

微服务全部知识点总结

目录

一、登录模块

1.1 依赖

1.2 数据库设计(多对多)

1.3 三个实体类   entity   都在security模块里面

1.4 UserDetailsService   service   不能放在security模块中

1.5 组件  component

1.6 认证、授权 

1.7 配置类    登录的url不用放行

1.8 授权注解

二、代码生成器

 2.1 依赖

2.2 配置文件

2.3 注解

2.4 代码

2.5 maven 编译xml文件

三、redis做缓存

 3.1 依赖

3.2 配置类

3.3 配置文件

3.4 注解

​编辑 3.5 使用

四、Common工具类

 4.1 reponse响应json工具类

4.2 统一返回结果R

4.3 ResultCode

五、pom文件

5.1 父工程依赖   springboot springcloud springcloud-alibaba

六、mybatis-plus

 6.1 数据库连接

 6.2 mybatis-plus

6.3 配置类 

6.4 datetime对应实体属性

6.5 自动填充时间 

6.6 分页

 6.7 驼峰匹配出错

6.8 多对多插入数据

6.9 更新数据 

6.10 逻辑删除

 6.11 手写sql插入时间 

6.12 动态sql

七、swagger

7.1 配置类

八、Nacos

8.1 安装

8.2 无法访问

8.3 依赖

8.4 注册中心

九、网关

9.1 配置文件

9.2 跨域

十、docker命令

10.1 查看docker 镜像

10.2 查看正在运行的镜像

10.3 删掉容器

10.4  删除镜像

10.5 启动redis

10.6 安装mysql 5.7

10.7 安装redis 

十一、前端

11.1 request.js的封装

11.2 post请求

 11.3 table修改数据

11.4 粒子特效

11.5 文字生成图片

11.6 走马灯

11.7 图片展示 

十二、Test 

12.1  测试

十三、vue-template

 13.1 修改请求地址

13.2 修改状态码 

13.3 后端对应接口

十四、文件上传

14.1 前端

14.2  依赖

14.3 配置文件

14.4 启动类

 14.5 配置类

14.6 获取服务端签名

14.6 保存到数据库

十五、日志记录

15.1 依赖

 15.2 log4j2.xml

15.3 配置文件

15.4 工具类

15.5 切面

十六、统一异常处理

16.1 异常类

十七、配置中心

17.1 依赖

17.2 配置

十八、docker远程连接

18.1 docker远程连接

十九、RabbitMQ

19.1 依赖

19.2 配置文件

19.3 配置类 

19.4 发送消息类

 19.5 封装交换机,roudingkey

19.6 接收类

二十、远程调用

20.1 依赖

20.2 feign下的类

20.3 注解


一、登录模块

RedisConfig属于公共模块

common => security => service

结构

1.1 依赖

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency></dependencies>

1.2 数据库设计(多对多)

1.3 三个实体类   entity   都在security模块里面

用户信息实体类    基本和数据库里面的属性一致

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserMessage {private Integer id;private String name;private String pwd;private String introduction;private String roles;private String avatar;
}

 SecurityUser

import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;@Data
public class SecurityUser implements UserDetails {//当前登录用户private UserMessage userMessage;//当前权限private List<String> permissionValueList;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {Collection<GrantedAuthority> authorities = new ArrayList<>();for(String permission:permissionValueList){if(StringUtils.isEmpty(permission)) continue;authorities.add(new SimpleGrantedAuthority(permission));}return authorities;}@Overridepublic String getPassword() {return userMessage.getPassword();}@Overridepublic String getUsername() {return userMessage.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}

LoginUser    用来读取前端传过来的用户名和密码

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginUser {private String username;private String password;
}

1.4 UserDetailsService   service   不能放在security模块中


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {@Autowiredprivate UsersService umsAdminService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {Users umsAdmin = umsAdminService.getUserByName(username);if(umsAdmin == null){throw new UsernameNotFoundException("用户不存在!");}SecurityUser securityUser = new SecurityUser();//添加用户信息securityUser.setUserMessage(umsAdmin);//添加权限信息List<String> roles = new ArrayList<>();roles.add(umsAdmin.getRoles());securityUser.setPermissionValueList(roles);return securityUser;}
}

1.5 组件  component

未认证


import lombok.SneakyThrows;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {@SneakyThrows@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e)throws IOException, ServletException {ResponseUtil.out(response, CommonResult.failed());}
}

Token

import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;import java.util.Date;
@Component
public class TokenManager {private static final long tokenExpiration = 24*60*60*1000;private static final String tokenSignKey = "runtothetop";//通过用户名加密public  String createToken(String username) {String token = Jwts.builder().setSubject(username).setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)).signWith(SignatureAlgorithm.HS512, tokenSignKey)pressWith(CompressionCodecs.GZIP)pact();return token;}//解密出用户名public  String getUserFromToken(String token) {String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();return user;}}

登出


import lombok.SneakyThrows;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class TokenLogoutHandler implements LogoutHandler {private TokenManager tokenManager;private RedisTemplate redisTemplate;public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;}@SneakyThrows@Overridepublic void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {String token = request.getHeader("Authorization");if (token != null) {//清空当前用户缓存中的权限数据String userName = tokenManager.getUserFromToken(token);redisTemplate.delete(userName);}ResponseUtil.out(response, CommonResult.success("登出成功"));}}

没有权限 


import lombok.SneakyThrows;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyAccessDenied implements AccessDeniedHandler {@SneakyThrows@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, AccessDeniedException e){ResponseUtil.out(response, CommonResult.failed(ResultCode.FORBIDDEN));}
}
    //没有权限@ExceptionHandler(AccessDeniedException.class)@ResponseBodypublic R AccessDenied(Exception ex){return R.failed(FORBIDDEN);}

1.6 认证、授权 

login

package com.yiyan.security.filter;import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {private AuthenticationManager authenticationManager;private TokenManager tokenManager;private RedisTemplate<String,Object> redisTemplate;public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {this.authenticationManager = authenticationManager;this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;this.setPostOnly(false);this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/back/login","POST"));}@SneakyThrows@Overridepublic Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse response)throws AuthenticationException {LoginUser user = new ObjectMapper().readValue(req.getInputStream(), LoginUser.class);return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));}@SneakyThrows@Override  //登录成功protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,FilterChain chain, Authentication auth) throwsIOException, ServletException {SecurityUser user = (SecurityUser) auth.getPrincipal();String token = tokenManager.createToken(user.getUsername());redisTemplate.opsForValue().set(user.getUsername(), JSON.toJSON(user).toString());Map<String, String> tokenMap = new HashMap<>();tokenMap.put("token", token);ResponseUtil.out(response, R.success(tokenMap));}//登陆失败@SneakyThrowsprotected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,AuthenticationException e) throws IOException, ServletException {ResponseUtil.out(response,R.failed());}
}

授权 

import com.alibaba.fastjson.JSON;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;// 自定义的授权过滤器
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {// token 管理器private TokenManager tokenManager;// redis 操作对象private RedisTemplate redisTemplate;public TokenAuthenticationFilter(AuthenticationManager authenticationManager,TokenManager tokenManager, RedisTemplate redisTemplate) {super(authenticationManager);this.redisTemplate = redisTemplate;this.tokenManager = tokenManager;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {// 获取当前登录认证成功的用户的权限信息UsernamePasswordAuthenticationToken auth = getAuthentication(request);// 如果有权限的信息,放入 SpringSccurity 权限的上下文中if (auth != null) {SecurityContextHolder.getContext().setAuthentication(auth);}// 放行操作doFilter(request, response, chain);}private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {// 从请求头获取 tokenString token = request.getHeader("Authorization");// 若 token 信息存在if (token != null) {// 从 token 中得到用户名String username = tokenManager.getUserFromToken(token);// 从 redis 获取权限的列表集合Object o = redisTemplate.opsForValue().get(username);SecurityUser user = JSON.parseObject(o.toString(), SecurityUser.class);List<String> permissions_list = user.getPermissionValueList();/*把权限列表的普通 List 集合遍历,将其每一个元素放入泛型为 GrantedAuthority 类型的 Collection<GrantedAuthority> 集合 authorities 中*/Collection<GrantedAuthority> authorities = new ArrayList<>();for (String s : permissions_list) {SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(s);authorities.add(simpleGrantedAuthority);}// Collection<? extends GrantedAuthority>return new UsernamePasswordAuthenticationToken(username, token, authorities);}return null;}
}

1.7 配置类    登录的url不用放行


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;import java.util.Arrays;@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenSecurityConfig extends WebSecurityConfigurerAdapter {private TokenManager tokenManager;private RedisTemplate<String,Object> redisTemplate;private UserDetailsService userDetailsService;@Autowiredpublic TokenSecurityConfig(UserDetailsService userDetailsService,TokenManager tokenManager, RedisTemplate redisTemplate) {this.userDetailsService = userDetailsService;this.tokenManager = tokenManager;this.redisTemplate = redisTemplate;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.exceptionHandling().accessDeniedHandler(new MyAccessDenied()).authenticationEntryPoint(new UnauthorizedEntryPoint()).and().csrf().disable().authorizeRequests().anyRequest().authenticated().and().logout().logoutUrl("/backstage/logout").addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and().addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate)).addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();}@BeanFilterRegistrationBean<CorsFilter> corsFilter() {FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.setAllowedHeaders(Arrays.asList("*"));corsConfiguration.setAllowedMethods(Arrays.asList("*"));corsConfiguration.setAllowedOrigins(Arrays.asList("*"));corsConfiguration.setMaxAge(3600L);UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", corsConfiguration);registrationBean.setFilter(new CorsFilter(source));registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);return registrationBean;}/*** 密码处理* @param auth* @throws Exception*/@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Beanpublic BCryptPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}/*** 配置哪些请求不拦截* @param web* @throws Exception*/@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/swagger-ui.html/**");}public static void main(String[] args) {BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();String str = encoder.encode("root");System.out.println(str);}}

1.8 授权注解

允许一个或多个

@PreAuthorize("hasAnyRole('admin',('root'))")

匹配时会默认为admin,root加上前缀ROLE_,所有数据库对应角色为:

 ROLE_admin,ROLE_root

二、代码生成器

 2.1 依赖

        <dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.0</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.0.5</version></dependency>

2.2 配置文件

mybatis-plus:configuration:#这个配置会将执行的sql打印出来,在开发或测试的时候可以用log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:#逻辑未删除值,(逻辑删除下有效)logic-delete-value: 1#逻辑未删除值,(逻辑删除下有效)需要注入逻辑策略LogicSqlInjector,以@Bean方式注              入logic-not-delete-value: 0#配置扫描xml# *.xml的具体路径#    - classpath*:/com/macro/mall/mapper/xml/*.xmlmapper-locations:classpath:/xml/*.xml#别名包扫描路径,通过该属性可以给包中的类注册别名,多个package用逗号或者分号分隔type-aliases-package: com.macro.mall.entity
secure:ignored:urls: #安全路径白名单- /swagger-ui.html- /swagger-resources/**- /swagger/**- /**/v2/api-docs- /**/*.js- /**/*.css- /**/*.png- /**/*.ico- /webjars/springfox-swagger-ui/**- /actuator/**- /druid/**- /admin/login- /admin/register- /admin/info- /admin/logout- /minio/upload

2.3 注解

 @MapperScan(basePackages = "com.macro.mall.mapper")

2.4 代码

package com.macro.mall.util;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;public class CodeGenerator {public static void main(String[] args) {// 1、创建代码生成器AutoGenerator mpg = new AutoGenerator();// 2、全局配置GlobalConfig gc = new GlobalConfig();String projectPath = System.getProperty("user.dir");System.out.println(projectPath);gc.setOutputDir("D:\\IDEA\\mail\\mail-admin" + "/src/main/java");gc.setAuthor("atguigu");gc.setOpen(false); //生成后是否打开资源管理器gc.setFileOverride(false); //重新生成时文件是否覆盖/** mp生成service层代码,默认接口名称第一个字母有 I* UcenterService* */gc.setServiceName("%sService");    //去掉Service接口的首字母Igc.setIdType(IdType.ID_WORKER_STR); //主键策略gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型gc.setSwagger2(true);//开启Swagger2模式mpg.setGlobalConfig(gc);// 3、数据源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setUrl("jdbc:mysql://localhost:8848/mall?serverTimezone=GMT%2B8");dsc.setDriverName("com.mysql.cj.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("12345678");dsc.setDbType(DbType.MYSQL);mpg.setDataSource(dsc);// 4、包配置PackageConfig pc = new PackageConfig();// pc.setModuleName("serviceedu"); //模块名pc.setParent("com.macro.mall");pc.setController("controller");pc.setEntity("entity");pc.setService("service");pc.setMapper("mapper");mpg.setPackageInfo(pc);// 5、策略配置StrategyConfig strategy = new StrategyConfig();//strategy.setInclude("edu_chapter", "edu_course", "edu_course_description", "edu_video");strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作strategy.setRestControllerStyle(true); //restful api风格控制器strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符mpg.setStrategy(strategy);// 6、执行mpg.execute();}
}

2.5 maven 编译xml文件

    <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>com.spotify</groupId><artifactId>docker-maven-plugin</artifactId></plugin></plugins><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources></build>

三、redis做缓存

 3.1 依赖

        <!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- spring2.X集成redis所需common-pool2--><dependency><groupId>org.apachemons</groupId><artifactId>commons-pool2</artifactId><version>2.6.0</version></dependency>

3.2 配置类

package com.atguigu.yyghmon.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.lang.reflect.Method;
import java.time.Duration;/*** @author lijian* @create 2021-04-25 15:40*/
@Configuration
@EnableCaching  // 开启缓存处理
public class RedisConfig {private RedisCacheManager build;/*** 自定义key规则** @return*/@Beanpublic KeyGenerator keyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {StringBuilder sb = new StringBuilder();sb.append(target.getClass().getName());sb.append(method.getName());for (Object obj : params) {sb.append(obj.toString());}return sb.toString();}};}/*** 设置RedisTemplate规则** @param redisConnectionFactory* @return*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//解决查询缓存转换异常的问题ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);//序列号key valueredisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}/*** 设置CacheManager缓存规则** @param factory* @return*/@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//解决查询缓存转换异常的问题ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);// 配置序列化(解决乱码的问题),过期时间600秒RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).disableCachingNullValues();RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();return cacheManager;}}

3.3 配置文件

spring.redis.host=192.168.220.130
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0spring:redis:host: localhostport: 6379database: 0timeout: 1800000jedis:pool:max-active: 20max-wait: 1max-idle: 5min-idle: 0

3.4 注解

 3.5 使用

 @Cacheable(value = "dict",keyGenerator = "keyGenerator")  //添加缓存

@CacheEvict(value = "dict", allEntries=true)  //表示清空缓存中的所有内容

四、Common工具类

 4.1 reponse响应json工具类

import com.alibaba.fastjson.JSON;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;public class ResponseUtil {public static void out(HttpServletResponse response,Object o)throws Exception{response.setContentType("application/json;charset=utf-8");PrintWriter out=response.getWriter();out.println(JSON.toJSON(o));out.flush();out.close();}
}

4.2 统一返回结果R

package com.yiyanmon.service.util;import java.util.Map;public class R {/*** 状态码*/private long code;/*** 提示信息*/private String message;/*** 数据封装*/private Object data;protected R() {}protected R(long code, String message, Object data) {this.code = code;this.message = message;this.data = data;}/*** 成功返回结果** @param data 获取的数据*/public static R success(Object data) {return new R(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);}public R data(Map<String, Object> map){return new R(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), map);}/*** 成功返回结果** @param data 获取的数据* @param  message 提示信息*/public static R success(Object data, String message) {return new R(ResultCode.SUCCESS.getCode(), message, data);}public static R success() {return new R(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), null);}/*** 失败返回结果* @param errorCode 错误码*/public static R failed(ResultCode errorCode) {return new R(errorCode.getCode(), errorCode.getMessage(), null);}/*** 失败返回结果*/public static R failed() {return failed(ResultCode.FAILED);}public long getCode() {return code;}public void setCode(long code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}}

4.3 ResultCode

package com.yiyanmon.service.util;public enum ResultCode {SUCCESS(200, "操作成功"),FAILED(500, "操作失败"),VALIDATE_FAILED(404, "参数检验失败"),UNAUTHORIZED(401, "暂未登录或token已经过期"),FORBIDDEN(403, "没有相关权限");private long code;private String message;private ResultCode(long code, String message) {this.code = code;this.message = message;}public long getCode() {return code;}public String getMessage() {return message;}
}

五、pom文件

5.1 父工程依赖   springboot springcloud springcloud-alibaba

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0"xmlns:xsi=""xsi:schemaLocation=".0.0 .0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.yiyin</groupId><artifactId>Distributed-YiYan</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>common</module><module>service</module><module>gateway</module><module>security</module></modules><!--    springboot--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version></parent><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.3.12.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.3.12.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><version>2.3.12.RELEASE</version></dependency>
<!--            spring-cloud--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR12</version><type>pom</type><scope>import</scope></dependency>
<!--            spring-cloud-alibaba--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.6.RELEASE</version><type>pom</type><scope>import</scope></dependency>
<!--            mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency>
<!--            druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.23</version></dependency>
<!--            mysql-connector--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency>
<!--            lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.20</version></dependency>
<!--            swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency>
<!--            swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency>
<!--            fastjson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.79</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.6.0</version></dependency></dependencies></dependencyManagement></project>

六、mybatis-plus

 6.1 数据库连接

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.44.128:3306/dis_yiyan?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername: rootpassword: rootdruid:initial-size: 5 #连接池初始化大小min-idle: 10 #最小空闲连接数max-active: 20 #最大连接数

 6.2 mybatis-plus

mybatis-plus:configuration:#这个配置会将执行的sql打印出来,在开发或测试的时候可以用log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#  global-config:
#    db-config:
#      #逻辑未删除值,(逻辑删除下有效)
#      logic-delete-value: 1
#      #逻辑未删除值,(逻辑删除下有效)需要注入逻辑策略LogicSqlInjector,以@Bean方式注              入
#      logic-not-delete-value: 0
#      #配置扫描xml# *.xml的具体路径
#      #    - classpath*:/com/macro/mall/mapper/xml/*.xmlmapper-locations:classpath:/mapper/*.xml#别名包扫描路径,通过该属性可以给包中的类注册别名,多个package用逗号或者分号分隔type-aliases-package: com.yiyan.service.backstage.pojo

6.3 配置类 

package com.yiyanmon.service;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan("com.yiyan.service.backstage.mapper")
public class MybatisPlusConfig {/*** 分页插件* @return*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 向MyBatis-Plus的过滤器链中添加分页拦截器,需要设置数据库类型(主要用于分页方言)interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}}

6.4 datetime对应实体属性

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")private Date createTime;

6.5 自动填充时间 

    @TableField(value = "create_time",fill = FieldFill.INSERT)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")private Date createTime;/*** */@TableField(value = "modify_time",fill = FieldFill.INSERT_UPDATE)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")private Date modifyTime;
package com.yiyanmon.serviceponent;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {this.strictInsertFill(metaObject, "createTime", Date.class, new Date());//LocalDateTime.class,LocalDateTime.now() 有时候这个行,有时候那个行this.strictInsertFill(metaObject, "modifyTime",  Date.class, new Date());}@Overridepublic void updateFill(MetaObject metaObject) {this.strictUpdateFill(metaObject, "modifyTime", LocalDateTime.class,LocalDateTime.now());}
}

6.6 分页

package io.renren.modules.stm.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.renrenmon.utils.R;
import io.renren.modules.stm.dao.StmDataDao;
import io.renren.modules.stm.entity.StmDataEntity;
import io.renren.modules.stm.service.PageService;
import io.renren.modules.stm.vo.PageVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service
public class PageServiceImpl implements PageService {@Autowiredprivate StmDataDao stmDataDao;@Overridepublic R page(PageVo pageVo) {QueryWrapper<StmDataEntity> wrapper = new QueryWrapper<>();//当前页是1,每页2条记录Page<StmDataEntity> page = new Page<>(pageVo.getPage(),pageVo.getLength());Page<StmDataEntity> pages = stmDataDao.selectPage(page, wrapper);//数据集合List<StmDataEntity> records = pages.getRecords();//总记录数long total = pages.getTotal();Map<String,Object> map = new HashMap<>();map.put("data",records);map.put("total",total);return R.ok(map);}
}

 6.7 驼峰匹配出错

@TableField(value = "create_time")

6.8 多对多插入数据

    void contextLoads() {ImgEntity imgEntity = new ImgEntity();imgEntity.setDeleted(0);imgEntity.setPath(".jpg");ImgRelationSuffix imgRelationSuffix = new ImgRelationSuffix();for(int i=0;i<9;i++){if(i%2==0){imgEntity.setName(i+".jpg");}else if(i%3==0){imgEntity.setName(i+".png");}else {imgEntity.setName(i+".gif");}mapper.insert(imgEntity);Integer imgId = imgEntity.getImgId();imgRelationSuffix.setImgId(imgId);imgRelationSuffix.setSuffixId(0);relationSuffixMapper.insert(imgRelationSuffix);}}

6.9 更新数据 

1.@ 根据id更新

User user = new User();
user.setUserId(1);
user.setAge(29);
userMapper.updateById(user);

 2.@ 条件构造器作为参数进行更新

//把名字为rhb的用户年龄更新为18,其他属性不变
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name","rhb");
User user = new User();
user.setAge(18);
userMapper.update(user, updateWrapper);

3.@ lambda构造器

LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(User::getName, "rhb").set(User::getAge, 18);
Integer rows = userMapper.update(null, lambdaUpdateWrapper);

6.10 逻辑删除

    /*** 0显示  1不显示*/@TableLogic(value = "0",delval = "1")private Integer deleted;
imgEntityService.removeById(id);

 

 6.11 手写sql插入时间 

    public void recovery(Integer id) {LocalDateTime dateTime = LocalDateTime.now();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");String time = dateTime.format(formatter);imgEntityMapper.recovery(id,time);}
<!--    void recovery(@Param("id") Integer id,@Param("time") String time);--><update id="recovery">update img_entity set deleted=0,modify_time=#{time} where deleted=1 and img_id=#{id}</update>

6.12 动态sql

    <select id="searchByCon" resultType="com.yiyan.service.backstage.vo.ImgVo">select e.img_id,e.name,e.path,e.suffix,x.type,e.deleted,e.create_time,e.modify_time fromimg_entity einner join img_relation_type r on e.img_id=r.img_idinner join img_type x on x.type_id=r.type_id<where><if test="vo.id != null">e.img_id = #{vo.id}</if><if test="vo.suffix != null">and e.suffix = #{vo.suffix}</if><if test="vo.name!= null">and e.name = #{vo.name}</if><if test="vo.type != null">and x.type_id = #{vo.type}</if><if test="vo.del != null">and e.deleted = #{vo.del}</if></where>order by e.img_id desclimit #{vo.index},#{vo.length};</select>

七、swagger

7.1 配置类

package com.yiyanmon.service.config;import com.googlemon.base.Predicates;
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.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration
@EnableSwagger2
public class Swagger2Config {@Beanpublic Docket webApiConfig(){return new Docket(DocumentationType.SWAGGER_2).groupName("webApi").apiInfo(webApiInfo()).select()
//                .paths(Predicates.not(PathSelectors.regex("/admin/.*"))).paths(Predicates.not(PathSelectors.regex("/error.*"))).build();}private ApiInfo webApiInfo(){return new ApiInfoBuilder().title("网站-课程中心API文档").description("本文档描述了课程中心微服务接口定义").version("1.0")//.contact(new Contact("Helen", "", "55317332@qq")).build();}
}

八、Nacos

8.1 安装

Docker安装Nacos详细教程 - nulitao - 博客园##一、拉取镜像 在命令行窗口输入以下命令,我这里是指定了版本号的;不指定版本号默认下载最新的。 docker pull nacos/nacos-server:1.3.1 如下这种情况就是在下载中,稍.html

8.2 无法访问


Docker启动Nacos,但是windows页面无法访问_我只会跳一下的博客-CSDN博客_docker安装nacos无法访问=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-5-122852485-blog-122405520.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-5-122852485-blog-122405520.pc_relevant_aa&utm_relevant_index=8

8.3 依赖


<!--         nacos的注册中心--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--服务调用--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
<!--        配置中心--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency>
<!--        gateway 核心依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>

如果引入了配置中心的依赖而没有配置,则会报错。

8.4 注册中心

spring:application:name: service-backstagecloud:nacos:discovery:server-addr: 192.168.44.128:8848

注解

 注册中心  @EnableDiscoveryClient

九、网关

        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>

9.1 配置文件

server.port=20000
#服务名称
spring.application.name=gateway
spring.cloud.nacos.discovery.server-addr=192.168.2.1:8840#使用服务发现路由
spring.cloud.gateway.discovery.locator.enabled=true#名称
spring.cloud.gateway.routes[0].id=service-edu
#服务注册中心的名称
spring.cloud.gateway.routes[0].uri=lb://service-edu
#路径匹配
spring.cloud.gateway.routes[0].predicates= Path=/eduservice/**#名称
spring.cloud.gateway.routes[1].id=service-oss
#服务注册中心的名称
spring.cloud.gateway.routes[1].uri=lb://service-oss
#路径匹配
spring.cloud.gateway.routes[1].predicates= Path=/oss/**

9.2 跨域

package com.yiyan.gateway.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;/*** <p>* 处理跨域* </p>*/
@Configuration
public class CorsConfig {@Beanpublic CorsWebFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();config.addAllowedMethod("*");config.addAllowedOrigin("*");config.addAllowedHeader("*");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());source.registerCorsConfiguration("/**", config);return new CorsWebFilter(source);}
}

十、docker命令

10.1 查看docker 镜像

docker  images

10.2 查看正在运行的镜像

docker ps

10.3 删掉容器

docker stop $(docker ps -qa)
docker rm $(docker ps -qa)

10.4  删除镜像

docker rmi --force $(docker images -q)

10.5 启动redis


docker启动redis简单方法=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-1-124399997-blog-108785774.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-1-124399997-blog-108785774.pc_relevant_aa&utm_relevant_index=2

10.6 安装mysql 5.7

docker pull mysql:5.7

查看docker镜像

 docker images

删除镜像

 docker rm + id

启动mysql

docker run -p 3306:3306 --name mysql \

--restart=always \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

进入mysql镜像

 docker exec -it mysql /bin/bash

修改字符集为utf-8

 在映射的conf文件夹下创建myf文件

[client]                  

default-character-set=utf8

[mysqld]

character-set-server=utf8

collation-server=utf8_general_ci

查看镜像运行状态

 docker ps

启动失败时查看日志

 docker logs --since 30m

docker logs mysql

重启mysql 

 docker restart mysql

10.7 安装redis 

安装镜像 

docker pull redis:6.0.10

启动

 mkdir -p /mydata/redis/conf

touch /mydata/redis/conf/redis.conf 

docker run --name redis -p 6379:6379 \

-v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis:6.0.10 redis-server /etc/redis/redis.conf

持久化存储

 打开mydata下的redis.conf

appendonly yes

连接客户端

 docker exec -it redis redis-cli

十一、前端

11.1 request.js的封装

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'// create an axios instance
const service = axios.create({baseURL: 'http://localhost:20000', // url = base url + request url process.env.VUE_APP_BASE_API// withCredentials: true, // send cookies when cross-domain requeststimeout: 5000 // request timeout
})// request interceptor
service.interceptors.request.use(config => {// do something before request is sentconfig.headers['Content-Type'] = 'application/json;charset=utf-8';if (store.getters.token) {// let each request carry token// ['X-Token'] is a custom headers key// please modify it according to the actual situationconfig.headers['X-Token'] = getToken()}return config},error => {// do something with request errorconsole.log(error) // for debugreturn Promise.reject(error)}
)// response interceptor
service.interceptors.response.use(/*** If you want to get http information such as headers or status* Please return  response => response*//*** Determine the request status by custom code* Here is just an example* You can also judge the status by HTTP Status Code*/response => {const res = response.data// if the custom code is not 20000, it is judged as an error.if (res.code !== 200) {Message({message: res.message || 'Error',type: 'error',duration: 5 * 1000})// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;if (res.code === 50008 || res.code === 50012 || res.code === 50014) {// to re-loginMessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {confirmButtonText: 'Re-Login',cancelButtonText: 'Cancel',type: 'warning'}).then(() => {store.dispatch('user/resetToken').then(() => {location.reload()})})}return Promise.reject(new Error(res.message || 'Error'))} else {return res}},error => {console.log('err' + error) // for debugMessage({message: error.message,type: 'error',duration: 5 * 1000})return Promise.reject(error)}
)export default service

11.2 post请求

    import request from "@/utils/request";request.post('/back/list',this.currentPage).then(res => {console.log(res.data)})request.post('/back/modify',{id:row.imgId,name:row.name,type:row.type}).then(res => {row.editor = false;})

 11.3 table修改数据

1、为展示数据添加属性   editor  默认false

2、字段

        <el-table-columnprop="type"label="类型"><template slot-scope="scope"><input type="text" v-model="scope.row.type" v-show="scope.row.editor" style="width: 80px"/><span v-show="!scope.row.editor">{{scope.row.type}}</span></template></el-table-column><el-table-column

 3、修改按钮

        <el-table-columnlabel="修改"align="right"><template slot-scope="scope"><el-buttonsize="mini"v-show="!scope.row.editor"@click="handleEdit(scope.$index, scope.row)">编辑</el-button><el-buttonsize="mini"v-show="scope.row.editor"@click="cancle(scope.$index, scope.row)">取消</el-button><el-buttonsize="mini"v-show="scope.row.editor"@click="submit(scope.$index, scope.row)">完成</el-button></template></el-table-column>

4、对应方法

    handleEdit(index, row) {row.editor = true;},handleDelete(index, row) {console.log(index, row);},cancle(index, row) {row.editor = false;},submit(index, row) {request.post('/back/modify',{id:row.imgId,name:row.name,type:row.type}).then(res => {row.editor = false;})},

11.4 粒子特效

1、安装插件

npm install vue-particles --save-dev

2、在main.js文件中全局引入 

import Vue from 'vue'
import VueParticles from 'vue-particles'
Vue.use(VueParticles)

3、在需要使用粒子背景的组件中使用(一般是首页或者登陆背景中使用) 

<template><div><el-row style="background-color: #ffffff"type="flex"justify="center"align="middle"><el-col :span="2"><div class="grid-content bg-purple"><img :src="i1" alt="qqq" width="80px"></div></el-col><el-col :span="4" type="flex"><div class="grid-content bg-purple" style="text-align: center"><img :src="i4" alt="qqq" width="80px"></div></el-col><el-col :span="2"><div class="grid-content bg-purple"><img :src="i3" alt="qqq" width="50px"></div></el-col><el-col :span="8"><div class="grid-content bg-purple" style="text-align: center"><img :src="y" alt="qqq" width="240px"></div></el-col><el-col :span="2"><div class="grid-content bg-purple"><img :src="i5" alt="qqq" width="90px"></div></el-col><el-col :span="4"><div class="grid-content bg-purple"><img :src="i6" alt="qqq" width="130px"></div></el-col><el-col :span="2"><div class="grid-content bg-purple"><img :src="i2" alt="qqq" width="40px"></div></el-col></el-row><div class="box"><vue-particlesclass="login-bg"color="#39AFFD":particleOpacity="0.7":particlesNumber="100"shapeType="circle":particleSize="4"linesColor="#8DD1FE":linesWidth="1":lineLinked="true":lineOpacity="0.4":linesDistance="150":moveSpeed="3":hoverEffect="true"hoverMode="grab":clickEffect="true"clickMode="push"></vue-particles><div class="other"><el-carousel :interval="4000" type="card" height="200px"><el-carousel-item v-for="item in 6" :key="item"><h3 class="medium">{{ item }}</h3></el-carousel-item></el-carousel></div></div></div>
</template><script>
import { mapGetters } from 'vuex'
import request from "@/utils/request";export default {name: 'Dashboard',data(){return{i1:require('../../assets/images/b1.jpg'),i2:require('../../assets/images/b2.jpg'),i3:require('../../assets/images/b3.jpg'),i4:require('../../assets/images/b4.jpg'),i5:require('../../assets/images/b5.jpg'),i6:require('../../assets/images/b6.jpg'),y:require('../../assets/images/y.gif'),}},methods:{test(){request({url: '/back/test',method: 'post',}).then(res => {alert(res.data)})}},computed: {...mapGetters(['name'])}
}
</script><style lang="scss" scoped>#particles-js{width: 100%;height: 100%;position: absolute;   //设置absolute,其他DIV设置为relative,这样这个例子效果就作为背景}.el-carousel__item h3 {color: #475669;font-size: 14px;opacity: 0.75;line-height: 200px;margin: 0;}.el-carousel__item:nth-child(2n) {background-color: #99a9bf;}.el-carousel__item:nth-child(2n+1) {background-color: #d3dce6;}.other{position: relative;}
</style>

属性: 

color: String类型。默认’#dedede’。粒子颜色。
particleOpacity: Number类型。默认0.7。粒子透明度。
particlesNumber: Number类型。默认80。粒子数量。
shapeType: String类型。默认’circle’。可用的粒子外观类型有:“circle”,“edge”,“triangle”, “polygon”,“star”。
particleSize: Number类型。默认80。单个粒子大小。
linesColor: String类型。默认’#dedede’。线条颜色。
linesWidth: Number类型。默认1。线条宽度。
lineLinked: 布尔类型。默认true。连接线是否可用。
lineOpacity: Number类型。默认0.4。线条透明度。
linesDistance: Number类型。默认150。线条距离。
moveSpeed: Number类型。默认3。粒子运动速度。
hoverEffect: 布尔类型。默认true。是否有hover特效。
hoverMode: String类型。默认true。可用的hover模式有: “grab”, “repulse”, + “bubble”。
clickEffect: 布尔类型。默认true。是否有click特效。
clickMode: String类型。默认true。可用的click模式有: “push”, “remove”, “repulse”, “bubble”

11.5 文字生成图片

文字生成图片.aspx

11.6 走马灯

        <div><el-carousel :interval="4000" type="card" height="320px"><el-carousel-item v-for="item in v" :key="item"><video preload="none" loop autoplay  muted width="100%" :poster="item[1]"><!-- 后缀是mp4 type类型就为mp4 --><source :src="item[0]" type="video/mp4"></video></el-carousel-item></el-carousel></div>

11.7 图片展示 

          <el-row><el-col :span="8" v-for="url in urls"><div class="grid-content bg-purple-dark"><el-image:src="url"fit="fill":preview-src-list="urls"style="margin:10px 40px;height: 200px;border-radius: 20px;"></el-image></div></el-col></el-row>

十二、Test 

12.1  测试

包名一致

十三、vue-template

 13.1 修改请求地址

13.2 修改状态码 

13.3 后端对应接口

    @RequestMapping("/login")public R login(){Map<String,Object> map = new HashMap<>();map.put("token","admin-token");return R.success(map);}@RequestMapping("/info")public R info(){Map<String,Object> map = new HashMap<>();map.put("avatar",".gif");map.put("introduction","I am a super administrator");map.put("name","admin");List<String> list = new ArrayList<>();list.add("admin");map.put("roles",list);return R.success(map);}

十四、文件上传

14.1 前端

<template><div class="app-container"><el-uploadaction="#"list-type="picture-card"accept=".jpg, .jpeg, .png,.gif":on-preview="handlePictureCardPreview":on-remove="handleimageDelete":on-change="handleimageChange":limit="10":auto-upload="false":multiple="true":file-list="fileList"><i class="el-icon-plus"></i></el-upload><div slot="tip" class="el-upload__tip">只能上传jpg/png/gif文件</div><el-dialog :visible.sync="dialogVisible"><img width="100%" :src="dialogImageUrl" alt=""></el-dialog><br/><br/><el-form ref="form" :model="image" label-width="80px"><el-form-item label="图片名称"><el-input v-model="image.name" style="width: 210px"></el-input></el-form-item><el-form-item label="图片类型"><el-select v-model="image.type" placeholder="请选择图片类型"><el-option label="二次元" value="0"></el-option><el-option label="风景" value="1"></el-option><el-option label="动物" value="2"></el-option></el-select></el-form-item><el-form-item><el-button :loading="loading" type="primary" @click="onSubmit">上传</el-button></el-form-item></el-form></div>
</template><script>
import request from "@/utils/request";
import axios from 'axios'export default {data() {return {fileList:null,file:null,dialogImageUrl: '',dialogVisible: false,loading:false,image:{path:null,suffix:null,name:null,type:null}}},methods: {//用于生成uuidS4() {return (((1+Math.random())*0x10000)|0).toString(16).substring(1);},guid() {return (this.S4()+this.S4()+"-"+this.S4()+"-"+this.S4()+"-"+this.S4()+"-"+this.S4()+this.S4()+this.S4());},beforeAvatarUpload (file) {let type= file.raw.typeif(type==='image/jpeg'||type==='image/jpg'){this.image.suffix='jpg'return true}else if(type==='image/png'){this.image.suffix='png'return true}else if(type==='image/gif'){this.image.suffix='gif'return true}this.$message.error('上传图片只能是 JPG PNG GIF格式!');return false},//点击查看图片handlePictureCardPreview(file) {this.dialogImageUrl = file.url;this.dialogVisible = true;},// 上传发生变化钩子handleimageChange(file, fileList) {//图片后缀不对this.fileList = fileList;this.file = filethis.image.name = this.file.nameconsole.log(this.file)},handleimageDelete(file, fileList){this.fileList = fileList;if(this.file === file){this.file = nullthis.image.name = nullthis.image.type = null}//  console.log(file)},onSubmit() {this.loading = true//图片为空if(this.file==null){this.$message.error('请选择要上传的图片');return;}if(!this.beforeAvatarUpload (this.file)){return}if(this.image.type==null||this.image.name==null||this.image.name.length===0){this.$message.error('图片名字或图片类型为空');return;}request.post('/oss/upload').then(res => {let data = res.datalet formData = new FormData();let filename = this.guid()+'.'+this.image.suffix//注意formData里append添加的键的大小写formData.append('key', data.dir + filename); //存储在oss的文件路径formData.append('OSSAccessKeyId', data.accessid); //accessKeyIdformData.append('policy', data.policy); //policyformData.append('Signature', data.signature); //签名//如果是base64文件,那么直接把base64字符串转成blob对象进行上传就可以了formData.append("file", this.file.raw);formData.append('success_action_status', 200); //成功后返回的操作码//图片地址this.image.path = data.host +'/'+ data.dir + filename;//上传axios({url: data.host,method:'post',data:formData,withCredentials:false,headers: {'Content-Type': 'multipart/form-data',},}).then(res=>{if(res.status==200){//成功回调request.post('/back/upload',this.image).then(res => {if(res.code==200){this.loading = falsethis.$message.success('上传成功!');}})}else{//失败回调this.$message.error('上传失败!');}})})},}
}
</script><style scoped>
.line{text-align: center;
}
</style>

14.2  依赖

        <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alicloud-oss</artifactId><version>2.1.0.RELEASE</version></dependency>

14.3 配置文件

spring:cloud:alicloud:access-key: LTAI5tGna5ngabSwwwaWWUCJfgegrrtrsMt6msecret-key: EcbYJbCrwuuuuuuutfdsQidh52LtjYQvoss:endpoint: oss-cn-beijing.aliyuncsbucket: gulimall-so

14.4 启动类

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@ComponentScan(basePackages = {"com.yiyan"})
@EnableDiscoveryClient
public class OssApplication {public static void main(String[] args) {SpringApplication.run(OssApplication.class,args);}
}

 14.5 配置类

package com.yiyan.service.oss.config;import com.aliyun.oss.OSSClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class OSSConfig {@Value("${spring.cloud.alicloud.access-key}")private String accessId;@Value("${spring.cloud.alicloud.secret-key}")private String secretId;@Value("${spring.cloud.alicloud.oss.endpoint}")private String endpoint;@Beanpublic OSSClient ossClient(){return new OSSClient(endpoint,accessId, secretId);}
}

14.6 获取服务端签名

package com.yiyan.service.oss.controller;import com.aliyun.oss.OSSClient;
import com.aliyun.ossmon.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.yiyanmon.service.util.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;@RestController
@RequestMapping("/oss")
public class OssController {@Autowiredprivate OSSClient ossClient;@Value("${spring.cloud.alicloud.access-key}")private String accessId;@Value("${spring.cloud.alicloud.oss.endpoint}")private String endpoint;@Value("${spring.cloud.alicloud.oss.bucket}")private String bucket;@RequestMapping("/upload")public R getPolicy() {String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint// callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。// String callbackUrl = ":8888";String formatDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());String dir = formatDate + "/"; // 用户上传文件时指定的前缀。Map<String, String> respMap = new LinkedHashMap<String, String>();try {long expireTime = 30;long expireEndTime = System.currentTimeMillis() + expireTime * 1000;Date expiration = new Date(expireEndTime);PolicyConditions policyConds = new PolicyConditions();policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);byte[] binaryData = postPolicy.getBytes("utf-8");String encodedPolicy = BinaryUtil.toBase64String(binaryData);String postSignature = ossClient.calculatePostSignature(postPolicy);respMap.put("accessid", accessId);respMap.put("policy", encodedPolicy);respMap.put("signature", postSignature);respMap.put("dir", dir);respMap.put("host", host);respMap.put("expire", String.valueOf(expireEndTime / 1000));} catch (Exception e) {// Assert.fail(e.getMessage());System.out.println(e.getMessage());} finally {ossClient.shutdown();}return R.success(respMap);}
}

14.6 保存到数据库

package com.yiyan.service.backstage.controller;import com.yiyanmon.service.util.R;
import com.yiyan.service.backstage.pojo.ImgEntity;
import com.yiyan.service.backstage.pojo.ImgRelationType;
import com.yiyan.service.backstage.service.ImgEntityService;
import com.yiyan.service.backstage.service.ImgRelationTypeService;
import com.yiyan.service.backstage.vo.param.UploadParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("back")
public class UploadController {@Autowiredprivate ImgEntityService imgEntityService;@Autowiredprivate ImgRelationTypeService typeService;@RequestMapping("/upload")public R upload(@RequestBody UploadParam param){ImgEntity imgEntity = new ImgEntity();ImgRelationType imgRelationType = new ImgRelationType();BeanUtils.copyProperties(param,imgEntity);imgEntity.setDeleted(0);imgEntityService.save(imgEntity);Integer imgId = imgEntity.getImgId();imgRelationType.setImgId(imgId);imgRelationType.setTypeId(param.getType());typeService.save(imgRelationType);return R.success();}
}

十五、日志记录

15.1 依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><!-- 排除 默认使用的logback  --><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><!-- log4j2 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency>

 15.2 log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF"><appenders><Console name="Console" target="SYSTEM_OUT"><!--只接受程序中DEBUG级别的日志进行处理--><ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/><PatternLayout pattern="[%d{HH:mm:ss.SSS}] %-5level %class{36} %L %M - %msg%xEx%n"/></Console><!--处理DEBUG级别的日志,并把该日志放到logs/debug.log文件中--><!--打印出DEBUG级别日志,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--><RollingFile name="RollingFileDebug" fileName="./logs/debug.log"filePattern="logs/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log.gz"><Filters><!--只接受DEBUG级别的日志,其余的全部拒绝处理--><ThresholdFilter level="DEBUG"/><ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/></Filters><!--输出日志的格式--><PatternLayoutpattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/><Policies><SizeBasedTriggeringPolicy size="500 MB"/><TimeBasedTriggeringPolicy/></Policies></RollingFile><!--处理INFO级别的日志,并把该日志放到logs/info.log文件中--><RollingFile name="RollingFileInfo" fileName="./logs/info.log"filePattern="logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz"><Filters><!--只接受INFO级别的日志,其余的全部拒绝处理--><ThresholdFilter level="INFO"/><ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/></Filters><PatternLayoutpattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/><Policies><SizeBasedTriggeringPolicy size="500 MB"/><TimeBasedTriggeringPolicy/></Policies></RollingFile><!--处理WARN级别的日志,并把该日志放到logs/warn.log文件中--><RollingFile name="RollingFileWarn" fileName="./logs/warn.log"filePattern="logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz"><Filters><ThresholdFilter level="WARN"/><ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/></Filters><PatternLayoutpattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/><Policies><SizeBasedTriggeringPolicy size="500 MB"/><TimeBasedTriggeringPolicy/></Policies></RollingFile><!--处理error级别的日志,并把该日志放到logs/error.log文件中--><RollingFile name="RollingFileError" fileName="./logs/error.log"filePattern="logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz"><ThresholdFilter level="ERROR"/><PatternLayoutpattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/><Policies><SizeBasedTriggeringPolicy size="500 MB"/><TimeBasedTriggeringPolicy/></Policies></RollingFile><!--druid的日志记录追加器--><RollingFile name="druidSqlRollingFile" fileName="./logs/druid-sql.log"filePattern="logs/$${date:yyyy-MM}/api-%d{yyyy-MM-dd}-%i.log.gz"><PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %L %M - %msg%xEx%n"/><Policies><SizeBasedTriggeringPolicy size="500 MB"/><TimeBasedTriggeringPolicy/></Policies></RollingFile></appenders><!--     然后定义logger,只有定义了logger并引入的appender,appender才会生效 --><loggers><!--默认的root的logger--><root level="DEBUG"><appender-ref ref="Console"/><appender-ref ref="RollingFileInfo"/><appender-ref ref="RollingFileWarn"/><appender-ref ref="RollingFileError"/><appender-ref ref="RollingFileDebug"/></root><!--额外配置的logger--><!--记录druid-sql的记录--><logger name="druid.sql.Statement" level="debug" additivity="false"><appender-ref ref="druidSqlRollingFile"/></logger><!--log4j2 自带过滤日志--><Logger name="org.apache.catalina.startup.DigesterFactory" level="error" /><Logger name="org.apache.catalina.util.LifecycleBase" level="error" /><Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" /><logger name="org.apache.sshdmon.util.SecurityUtils" level="warn"/><Logger name="org.apache.tomcat.util.NioSelectorPool" level="warn" /><Logger name="org.crsh.plugin" level="warn" /><logger name="org.crsh.ssh" level="warn"/><Logger name="org.eclipse.jetty.utilponent.AbstractLifeCycle" level="error" /><Logger name="org.hibernate.validator.internal.util.Version" level="warn" /><logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/><logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/><logger name="org.thymeleaf" level="warn"/></loggers>
</configuration>

15.3 配置文件

logging:config: classpath:log4j2.xml

15.4 工具类

 HttpContextUtils

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;/*** HttpServletRequest**/
public class HttpContextUtils {public static HttpServletRequest getHttpServletRequest() {return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();}}

 IpUtils

import lombok.extern.log4j.Log4j2;
import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;/*** 获取Ip**/
@Log4j2
public class IpUtils {/*** 获取IP地址* <p>* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址*/public static String getIpAddr(HttpServletRequest request) {String ip = null, unknown = "unknown", seperator = ",";int maxLength = 15;try {ip = request.getHeader("x-forwarded-for");if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (StringUtils.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");}if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}} catch (Exception e) {log.error("IpUtils ERROR ", e);}// 使用代理,则获取第一个IP地址if (StringUtils.isEmpty(ip) && ip.length() > maxLength) {int idx = ip.indexOf(seperator);if (idx > 0) {ip = ip.substring(0, idx);}}return ip;}/*** 获取ip地址** @return*/public static String getIpAddr() {HttpServletRequest request = HttpContextUtils.getHttpServletRequest();return getIpAddr(request);}
}

15.5 切面

LogAspect

package com.yiyan.service.backstage.aop;import com.alibaba.fastjson.JSON;
import com.yiyanmon.service.util.HttpContextUtils;
import com.yiyanmon.service.util.IpUtils;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;@Aspect
@Component
@Log4j2
public class LogAspect {//定义切面@Pointcut("execution(* com.yiyan.service.backstage.controller.*.*(..))")public void pointCut(){};//环绕通知@Around("pointCut()")public Object log(ProceedingJoinPoint point) throws Throwable {long beginTime = System.currentTimeMillis();//执行方法Object result = point.proceed();//执行时长(毫秒)long time = System.currentTimeMillis() - beginTime;//保存日志recordLog(point, time);return result;}private void recordLog(ProceedingJoinPoint joinPoint, long time) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();log.info("=====================log start================================");//请求的方法名String className = joinPoint.getTarget().getClass().getName();String methodName = signature.getName();log.info("request method:{}",className + "." + methodName + "()");//        //请求的参数Object[] args = joinPoint.getArgs();int length = args.length;if(length==0){log.info("params: null");}else{String params = JSON.toJSONString(args[0]);log.info("params:{}",params);}//获取request 设置IP地址HttpServletRequest request = HttpContextUtils.getHttpServletRequest();log.info("ip:{}", IpUtils.getIpAddr(request));log.info("excute time : {} ms",time);log.info("=====================log end================================");}}

十六、统一异常处理

16.1 异常类

AllExceptionHandler

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;//对加了@Controller注解的方法进行拦截处理
@ControllerAdvice
public class AllExceptionHandler {//进行异常处理,处理Exception.class的异常@ExceptionHandler(Exception.class)@ResponseBodypublic R doException(Exception ex){ex.printStackTrace();return R.failed();}}

十七、配置中心

17.1 依赖

        <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency>

17.2 配置

 

bootstrap.properties 

spring.cloud.nacos.config.server-addr=192.168.248.128:8848
spring.cloud.nacos.discovery.server-addr=192.168.248.128:8848
spring.application.name=service-ossspring.cloud.nacos.config.namespace=fbb1d224-3e0a-4629-860d-97c7318b96f5
spring.cloud.nacos.config.extension-configs[0].data-id=oss.yaml
spring.cloud.nacos.config.extension-configs[0].refresh=true

十八、docker远程连接

18.1 docker远程连接

安装

curl -fsSL | bash -s docker --mirror Aliyun

修改docker.service文件,添加监听端口 -H tcp://0.0.0.0:2375

  vi /usr/lib/systemd/system/docker.service

 找到 ExecStart,在最后面添加 -H tcp://0.0.0.0:2375,如下图所示

 

 重启docker

 systemctl daemon-reload
 systemctl start docker

关闭防火墙

firewall-cmd --query-port=2375/tcp

firewall-cmd --add-port=2375/tcp --permanent

firewall-cmd --reload

在File–> Settings–>Build,Execution,Deployment中找到Docker 

十九、RabbitMQ

19.1 依赖

        <!--rabbitmq消息队列--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId></dependency>

19.2 配置文件

#rabbitmq地址
spring.rabbitmq.host=192.168.220.130
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

19.3 配置类 

转换为json

import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author lijian* @create 2021-05-04 9:48*/@Configuration
public class MQConfig {@Beanpublic MessageConverter messageConverter() {return new Jackson2JsonMessageConverter();}
}

19.4 发送消息类

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** @author lijian* @create 2021-05-04 9:46*/@Service
public class RabbitService {@Autowiredprivate RabbitTemplate rabbitTemplate;/*** 发送消息** @param exchange   交换机* @param routingKey 路由键* @param message    消息*/public boolean sendMessage(String exchange, String routingKey, Object message) {rabbitTemplate.convertAndSend(exchange, routingKey, message);return true;}
}

 19.5 封装交换机,roudingkey

public class MqConst {/*** 预约下单*/public static final String EXCHANGE_DIRECT_ORDER = "exchange.direct.order";public static final String ROUTING_ORDER = "order";//队列public static final String QUEUE_ORDER = "queue.order";/*** 短信*/public static final String EXCHANGE_DIRECT_MSM = "exchange.direct.msm";public static final String ROUTING_MSM_ITEM = "msm.item";//队列public static final String QUEUE_MSM_ITEM = "queue.msm.item";//定时任务public static final String EXCHANGE_DIRECT_TASK = "exchange.direct.task";public static final String ROUTING_TASK_8 = "task.8";//队列public static final String QUEUE_TASK_8 = "queue.task.8";}

19.6 接收类

import com.atguigumon.rabbit.constant.MqConst;
import com.atguigumon.rabbit.service.RabbitService;
import com.atguigu.yygh.hosp.service.ScheduleService;
import com.atguigu.yygh.model.hosp.Schedule;
import com.atguigu.yygh.vo.msm.MsmVo;
import com.atguigu.yygh.vo.order.OrderMqVo;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.IOException;/*** @author lijian* @create 2021-05-04 10:21*/
@Component
public class HospitalReceiver {@Autowiredprivate ScheduleService scheduleService;@Autowiredprivate RabbitService rabbitService;@RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.QUEUE_ORDER, durable = "true"),exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_ORDER),key = {MqConst.ROUTING_ORDER}))public void receiver(OrderMqVo orderMqVo, Message message, Channel channel) throws IOException {if(null != orderMqVo.getAvailableNumber()) {//下单成功更新预约数Schedule schedule = scheduleService.getScheduleId(orderMqVo.getScheduleId());schedule.setReservedNumber(orderMqVo.getReservedNumber());schedule.setAvailableNumber(orderMqVo.getAvailableNumber());scheduleService.update(schedule);}else{//取消预约更新预约数Schedule schedule = scheduleService.getScheduleId(orderMqVo.getScheduleId());int availableNumber = schedule.getAvailableNumber().intValue() + 1;schedule.setAvailableNumber(availableNumber);scheduleService.update(schedule);}//发送短信MsmVo msmVo = orderMqVo.getMsmVo();if(null != msmVo) {rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM, MqConst.ROUTING_MSM_ITEM, msmVo);}}}

二十、远程调用

20.1 依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

20.2 feign下的类

package com.atguigu.gulimall.member.feign;import com.atguigumon.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;@FeignClient("gulimall-coupon")
public interface CouponFeignService {@RequestMapping("/coupon/coupon/member/list")public R memberCoupons();
}

20.3 注解

@EnableFeignClients(basePackages = "com.atguigu.gulimall.member.feign")

更多推荐

微服务全部知识点总结

本文发布于:2024-03-12 21:00:47,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1732412.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:知识点

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!