首页
归档
留言
友链
广告合作
壁纸
更多
美女主播
Search
1
博瑞GE车机升级/降级
5,577 阅读
2
Mac打印机设置黑白打印
4,888 阅读
3
修改elementUI中el-table树形结构图标
4,865 阅读
4
Mac客户端添加腾讯企业邮箱方法
4,646 阅读
5
intelliJ Idea 2022.2.X破解
4,317 阅读
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
登录
/
注册
Search
标签搜索
Spring Boot
Java
Vue
Spring Cloud
Mac
MyBatis
WordPress
asp.net
Element UI
Nacos
MacOS
.Net
Spring Cloud Alibaba
Mybatis-Plus
Typecho
jQuery
MySQL
Java Script
微信小程序
Oracle
Laughing
累计撰写
606
篇文章
累计收到
1,417
条评论
首页
栏目
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
页面
归档
留言
友链
广告合作
壁纸
美女主播
搜索到
97
篇与
的结果
2021-07-17
Spring Cloud Eureka配置集群
Eureka Server可以通过运行多个实例并通过相互注册的方式实现高可用性的部署。Eureka Server实例会彼此通过增量同步的方式同步信息,确保节点数据之间的一致性。配置hosts由于我这里部署到同一个电脑上,因此需要配置hosts,以便进行服务之间的区分。win电脑hosts文件位于:C:\Windows\System32\drivers\etc\hostsMac及Linux电脑hosts文件位于:/etc/hosts在hosts文件末尾增加以下内容:C:\Windows\System32\drivers\etc配置服务提供者分别创建两个Spring Boot应用,分别为microservice-discovery-eureka、microservice-discovery-eureka-ha,代表两个服务提供者工程。添加依赖两个工程,同时添加以下依赖。<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>修改启动类两个工程的启动类,分别添加@EnableEurekaServer注解。@SpringBootApplication @EnableEurekaServer public class MicroserviceDiscoveryEurekaApplication { public static void main(String[] args) { SpringApplication.run(MicroserviceDiscoveryEurekaApplication.class, args); } }microservice-discovery-eureka配置文件如下spring: application: name: microservice-discovery-eureka server: port: 8761 eureka: instance: hostname: peer1 appname: microservice-discovery-eureka prefer-ip-address: false client: serviceUrl: defaultZone: http://peer2:8762/eureka # false表示不向注册中心注册自己 register-with-eureka: true # false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: truemicroservice-discovery-eureka-ha配置文件如下spring: application: name: microservice-discovery-eureka server: port: 8762 eureka: instance: hostname: peer2 appname: microservice-discovery-eureka client: serviceUrl: defaultZone: http://peer1:8761/eureka # false表示不向注册中心注册自己 register-with-eureka: true # false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: true可以看到,两个工程通过相互注册的方式,实现集群。配置文件,需要注意以下内容[alt type="success"]hostname需要不同[/alt][alt type="info"]appname必须保持一致[/alt][alt type="warning"]defaultZone需要使用我们配置的IP映射,而不是使用IP[/alt]
2021年07月17日
1,002 阅读
0 评论
1 点赞
2021-07-17
spring boot 通过actuator监控应用程序
Spring Boot Actuator提供了很多的监控端点,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、环境变量、日志信息、线程信息等。我们可以使用http://{ip}/{port}/actuator/{endpoint}的形式访问这些端点。这些端点大部分是GET方法,当然也有POST方法,比如shutdown。actuator提供的部分端点如下表所示序号端点描述HTTP方法1conditions(老版本为autoconfig)显示自动配置的信息GET2beans显示应用程序所有的Spring beanGET3configprops显示所有@ConfigurationPropertiesGET4threaddump(老版本为dump)显示线程活动快照GET5env显示所有的环境变量GET6health显示应用程序的健康指标,如需显示详情,需要在配置文件配置management.endpoint.health.show-details=alwaysGET7info显示应用信息。GET8mappings显示所有@RequestMapping的路径列表GET9metrics显示应用的度量标准信息GET10shutdown关闭应用,默认关闭,需要在配置文件配置management.endpoint.shutdown=true开启POST11loggers显示日志信息GET12heapdump下载应用程序堆栈信息GET部分配置文件如下,具体内容看注释management: endpoint: beans: enabled: true health: # 显示详细信息 show-details: always shutdown: enabled: true endpoints: web: exposure: # 配置暴漏的端点 include: '*'
2021年07月17日
830 阅读
0 评论
0 点赞
2021-06-25
Spring Boot国际化
Spring Boot国际化虽然在目前项目上用的比较少,但是总归是要学习一ha(四声)的。添加Resource Bundle首先在resources文件夹下创建i18n文件夹,然后右键i18n创建Resource Bundle添加配置文件添加三个配置文件,分别是login.properties、login_en_US.properties、login_zh_CN.properties,分别对应默认的国际化配置、英文配置、中文配置。login.properties是默认的国际化配置文件,如果找不到国际化信息时,默认会读取login.properties的配置信息。这里为了演示,我只添加了一条信息,即login.password。login.propertieslogin.password=请输入密码login_en_US.propertieslogin.password=please input passwordlogin_zh_CN.propertieslogin.password=请输入密码[alt type="success"]温馨提示[/alt]批量选择配置文件后,右键点击,选择Combine to Resource Bundle,可以批量编辑国际化配置文件修改配置文件修改application.properties,配置国际化文件spring.messages.basename=i18n.login修改加载国际化配置国际化支持,我们默认通过前端传递的lang(放到header),读取对应的国际化信息。@Component public class MyLocaleResolverConfig implements LocaleResolver { private static final String PATH_PARAMETER = "lang"; private static final String PATH_PARAMETER_SPLIT = "_"; @Override public Locale resolveLocale(HttpServletRequest httpServletRequest) { String lang = httpServletRequest.getHeader(PATH_PARAMETER); Locale locale = httpServletRequest.getLocale(); if (!StringUtils.isEmpty(lang)) { String[] split = lang.split(PATH_PARAMETER_SPLIT); locale = new Locale(split[0], split[1]); } return locale; } @Override public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { } @Bean public LocaleResolver localeResolver() { return new MyLocaleResolverConfig(); } }增加读取配置文件工具增加MessageUtils.java,用于读取国际化配置信息@Component public class MessageUtils { @Resource private MessageSource messageSource; private static MessageSource staticMessageSource; @PostConstruct public void init() { MessageUtils.staticMessageSource = messageSource; } /** * 获取消息 * @param messageKey * @return */ public static String getMessage(String messageKey) { Locale locale = LocaleContextHolder.getLocale(); return staticMessageSource.getMessage(messageKey, null, locale); } }增加静态类增加配置文件key对应的静态类,方便读取配置文件。/** * Description: * * @author : laughing * DateTime: 2021-06-25 17:06 */ public class MessageKey { public static String LOGIN_PASSWORD="login.password"; }增加测试controller/** * Description: * * @author : laughing * DateTime: 2021-06-25 17:20 */ @RestController public class MessageController { @GetMapping("message") public String message(){ return MessageUtils.getMessage(MessageKey.LOGIN_PASSWORD); } }通过postman测试请求不带参数当我们不携带lang参数时,系统默认加载login.properties测试中文当我们测试中文时,lang参数携带zh_CN测试英文当我们测试中文时,lang参数携带en_US
2021年06月25日
1,149 阅读
0 评论
2 点赞
2021-06-11
Spring Boot 使用mybatis-plus逻辑删除选装件
试想一下我们的系统,我们所有的表都有五个字段,分别是创建者(create_by)、创建时间(create_time)、修改者(update_by)、修改时间(update_time)、删除标志(del_flag), 同时通过mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间。目前在数据库新增,能自动注入创建人、创建时间,修改时,能自动注入修改人、 修改时间。如果我们调用mybatis-plus提供的删除方法(deleteById),既然是逻辑删除,我们设想的肯定是此时能够自动注入修改人、修改时间,但是,实际测试你会发现,此时sql并没有注入修改人、修改时间。为了解决这个问题,mybatis-plus提供了一个LogicDeleteByIdWithFill的逻辑删除组装件。通过此方法,我们在进行逻辑删除时,便能自动注入修改人、修改时间。继承DefaultSqlInjector/** * Description:官方逻辑删除选装件 * * @author : laughing * DateTime: 2021-06-11 15:21 */ @Component public class MySqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); //2.官方选装件,逻辑删除时,自动填充其他字段(例如逻辑删除时,自动填充删除人是谁,什么时候删除的) methodList.add(new LogicDeleteByIdWithFill()); return methodList; } }配置逻辑删除插件/** * Mybatis-Plus配置 * * @author laughing */ @Configuration @EnableTransactionManagement public class MyBatisPlusConfig { @javax.annotation.Resource private Environment env; static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; private final Logger logger = LoggerFactory.getLogger(MyBatisPlusConfig.class); @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 如果用了分页插件注意先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor // 用了分页插件必须设置 MybatisConfiguration#useDeprecatedExecutor = false // interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); interceptor.addInnerInterceptor(new TenantLineInnerInterceptor( new TenantLineHandler() { // manager_id = 1088248166370832385 // 获取租户 ID 值表达式,只支持单个 ID 值 @Override public Expression getTenantId() { return new StringValue(SecurityUtils.getOrgCode()); } // 这是 default 方法,默认返回 false 表示所有表都需要拼多租户条件, // 这里设置 role表不需要该条件 @Override public boolean ignoreTable(String tableName) { logger.info("orgCode=======" + SecurityUtils.getOrgCode()); return StringUtils.isEmpty(SecurityUtils.getOrgCode()) || WisdomAgricultureConfig.getFilterTableList().stream().anyMatch(e -> e.equalsIgnoreCase(tableName)); } @Override public String getTenantIdColumn() { return "org_code"; } })); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); } public static String setTypeAliasesPackage(String typeAliasesPackage) { ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver(); MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver); List<String> allResult = new ArrayList<String>(); try { for (String aliasesPackage : typeAliasesPackage.split(",")) { List<String> result = new ArrayList<String>(); aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN; Resource[] resources = resolver.getResources(aliasesPackage); if (resources != null && resources.length > 0) { MetadataReader metadataReader = null; for (Resource resource : resources) { if (resource.isReadable()) { metadataReader = metadataReaderFactory.getMetadataReader(resource); try { result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } if (result.size() > 0) { HashSet<String> hashResult = new HashSet<String>(result); allResult.addAll(hashResult); } } if (allResult.size() > 0) { typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0])); } else { throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包"); } } catch (IOException e) { e.printStackTrace(); } return typeAliasesPackage; } public Resource[] resolveMapperLocations(String[] mapperLocations) { ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); List<Resource> resources = new ArrayList<Resource>(); if (mapperLocations != null) { for (String mapperLocation : mapperLocations) { try { Resource[] mappers = resourceResolver.getResources(mapperLocation); resources.addAll(Arrays.asList(mappers)); } catch (IOException e) { // ignore } } } return resources.toArray(new Resource[resources.size()]); } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage"); String mapperLocations = env.getProperty("mybatis-plus.mapperLocations"); String configLocation = env.getProperty("mybatis-plus.configLocation"); typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage); VFS.addImplClass(SpringBootVFS.class); final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setTypeAliasesPackage(typeAliasesPackage); sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ","))); sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); sessionFactory.setPlugins(mybatisSqlInterceptor(), mybatisPlusInterceptor()); sessionFactory.setGlobalConfig(globalConfig()); return sessionFactory.getObject(); } @Bean public MybatisSqlInterceptor mybatisSqlInterceptor() { MybatisSqlInterceptor mybatisSqlInterceptor = new MybatisSqlInterceptor(); Properties properties = new Properties(); mybatisSqlInterceptor.setProperties(properties); return mybatisSqlInterceptor; } /** * 逻辑删除插件 */ @Bean public GlobalConfig globalConfig() { GlobalConfig globalConfig = new GlobalConfig(); GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig(); dbConfig.setLogicDeleteValue("Y"); dbConfig.setLogicNotDeleteValue("N"); globalConfig.setDbConfig(dbConfig); globalConfig.setSqlInjector(sqlInjector()); return globalConfig; } /** * 自定义Sql注入器 */ @Bean public MySqlInjector sqlInjector() { return new MySqlInjector(); } }扩展BaseMapper/** * Description: * * @author : laughing * DateTime: 2021-06-11 15:23 */ public interface MyBaseMapper<T> extends BaseMapper<T> { /** * 逻辑删除,并且带自动填充 */ int deleteByIdWithFill(T entity); }修改Mapper接口修改Mapper接口,将原来继承BaseMapper改成我们自定义的MyBaseMapper/** * Description:红外测温 * * @author : laughing * DateTime: 2021-05-18 10:28 */ public interface CulturePigTemperatureMapper extends MyBaseMapper<CulturePigTemperature> { /** * 红外测温列表查询 * @param pig 查询条件 * @return 结果 */ List<CulturePigTemperature> selectCulturePigTemperatureList(CulturePig pig); }修改删除方法将原来的删除方法deleteById改成deleteByIdWithFill再次测试,可以看到修改人、修改时间字段能够在逻辑删除方法时自动注入。
2021年06月11日
1,722 阅读
0 评论
0 点赞
2021-06-11
Spring Boot解决fastjson序列化丢失小数点后零的问题
项目上使用数值类型(金额)时,比如价格,我们可能会将数值格式化成两位小数。比如12.34或者12.00。如果项目上使用FastJson进行序列化,你会发现如果我们金额是整数,比如12.00,FastJson序列化之后,返回到前端的是12而不是12.00。查阅FastJson文档,我们发现,在fastjson 1.2.16版本之后,JSONField支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化。实现ObjectSerializer接口第一步,我们实现ObjectSerializer,提供我们自己序列化的规则,如下/** * Description:FastJson金额序列化格式化成两位 * * @author : laughing * DateTime: 2021-06-11 11:49 */ public class Keep2Format implements ObjectSerializer { private DecimalFormat df = new DecimalFormat("0.00"); @Override public void write(JSONSerializer jsonSerializer, Object object, Object fieldName, Type type, int i) throws IOException { jsonSerializer.write(df.format(object)); } }@JSONField注解字段第二步,通过@JSONField设置我们自定义的序列化规则。@JSONField(serializeUsing = Keep2Format.class)再次查看数据,可以发现price字段已经格式化成两位小数。[alt type="info"]注意:此功能需要fastjson 1.2.16及之后的版本[/alt]
2021年06月11日
1,894 阅读
0 评论
0 点赞
2021-06-09
Spring Boot Session共享
正常情况下,HttpSession是通过Servlet容器创建并进行管理的。创建成功之后都是保存在内存中的。如果开发者需要对项目进行横向扩展搭建集群,那么可以利用一些硬件或者软件工具来做负载均衡,此时,来自同一个用户的HTTP请求就有可能被分发到不同的实例上去,如何保证各个实例之间Session的同步就成为了一个必须要解决的问题。Spring Boot提供了自动化的Session共享配置,它结合Redis可以非常方便的解决这个问题。使用Redis解决Session共享问题的原理非常简单,就是把原本存储在不同服务器上的Session拿出来放到一个独立的服务器上。添加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>配置redis修改配置文件,增加redis配置spring.redis.database=0 spring.redis.host=localhost spring.redis.port=6379创建controller测试@RestController public class RedidSessionController { @Value("${server.port}") public String port; @PostMapping("/save") public String saveName(String name, HttpSession session) { session.setAttribute("name", name); return "hello," + name + ":" + port; } @PostMapping("/get") public String getName(HttpSession session) { session.getAttribute("name"); return "hello," + session.getAttribute("name") + ":" + port; } }打包jar包通过mvn clean package打包成jar包。分别执行 java -jar demo-0.0.1-SNAPSHOT.jar --server.port=8080 java -jar demo-0.0.1-SNAPSHOT.jar --server.port=8081通过8080、8081两个端口运行配置nginx负载均衡主要配置内容如下upstream test.com{ server localhost:8080 weight=1; server localhost:8081 weight=1; } server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://test.com; root html; index index.html index.htm; } } 配置文件中首先配置上游服务器,即两个real server,权重都是1,也就是说,请求平均分配到8080及8081端口。测试我们通过postman,调用save方法,保存session信息。然后再次通过postman,调用get方法,可以看到,系统正确的获取到8080端口保存的session信息。再次打开redis,查看session信息可以看到,session信息正确保存到了我们配置的redis数据库中。
2021年06月09日
1,047 阅读
0 评论
1 点赞
2021-06-09
Spring Boot @WebServlet、@WebFilter、@WebListener的使用
三个注解都必须在启动类增加@ServletComponentScan才能够被扫描到。@WebServlet可用于根据不同条件,重定向请求至不同URL。示例代码@WebServlet(name = "/my") @Slf4j public class MyWebServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) { log.info("进入get方法"); log.info(req.getParameter("name")); doPost(req,resp); } @Override protected void doHead(HttpServletRequest req, HttpServletResponse resp) { log.info("进入get方法"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) { log.info("进入post方法"); log.info(req.getParameter("name")); } @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) { log.info("进入put方法"); } @Override protected void doDelete(HttpServletRequest req, HttpServletResponse resp) { log.info("进入delete方法"); } @Override protected void doOptions(HttpServletRequest req, HttpServletResponse resp) { log.info("进入option方法"); } @Override public void destroy() { log.info("servlet>>>destroy"); } @Override public void init() { log.info("servlet>>>init"); } } 使用postman分别通过get、post、delete等进行请求http://localhost:8080/my?name=张三,可以查看输出结果@WebFilter可用于拦截/过滤请求,提前对请求的request进行判断处理,在doFilter后过滤器放行,调用实际请求URL路径。示例代码@WebFilter("/my") @Slf4j public class MyWebFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("filter>>>init"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("进入doFilter方法"); filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { log.info("filter>>>destroy"); } }再次请求,查看输出结果[alt type="error"]注意看输出顺序[/alt]@WebListener在spring启动之前监听执行初始化操作,可用于提前加载缓存等。@WebListener @Slf4j public class MyWebListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent sre) { log.info("requestDestroyed"); } @Override public void requestInitialized(ServletRequestEvent sre) { log.info("requestInitialized"); } }输出结果
2021年06月09日
899 阅读
0 评论
0 点赞
2021-06-08
Spring Boot通过ApplicationRunner实现系统启动任务
在Spring Boot通过CommandLineRunner实现系统启动任务中我们介绍了通过CommandLineRunner实现启动任务。但是CommandLineRunner实现的启动任务,我们在传递入口参数时,只能传递基本类型,入法通过键值对的形式传递参数。ApplicationRunner的实现原理跟CommandLineRunner基本类似,我们终点说一下ApplicationRunner的用法。ApplicationRunner实现类中run()方法参数为ApplicationArguments,ApplicationArguments说明如下:通过getNonOptionArgs()获取基本参数,这个与CommandLineRunner的参数是一致的。通过getOptionNames()获取键。通过getOptionValues获取值。演示代码@Component @Order(1) @Slf4j public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) { List<String> nonOptionArgs = args.getNonOptionArgs(); Set<String> optionNames = args.getOptionNames(); List<String> optionValues = args.getOptionValues("name"); log.info("MyApplicationRunner>>>nonOptionArgs>>>" + nonOptionArgs.toString()); log.info("MyApplicationRunner>>>optionNames>>>" + optionNames.toString()); log.info("MyApplicationRunner>>>optionValues>>>" + optionValues.toString()); } }修改入口参数--name代表键,=后面是值,注意是--不是-
2021年06月08日
1,052 阅读
0 评论
0 点赞
2021-06-08
Spring Boot通过CommandLineRunner实现系统启动任务
所谓系统启动任务,是在系统启动时执行的一些操作,一般而言只在系统启动之时执行,并且一般只执行一次。比如加载配置文件、数据库初始化操作等。Spring Boot针对系统启动任务,提供了两种解决方案:一是实现CommandLineRunner接口另一种方式是实现ApplicationRunner接口。本文针对CommandLineRunner方式进行说明。Spring Boot项目在启动时,会遍历所有CommandLineRunner实现类并调用其中的run()方法。如果系统中有多个CommandLineRunner实现类,可以通过@Order()注解指定实现类的调用顺序,数值越小越先执行。 [typing]演示代码[/typing]MyCommandLineRunner1@Component @Order(1) @Slf4j public class MyCommandLineRunner1 implements CommandLineRunner { @Override public void run(String... args) throws Exception { log.info("Runner1>>>" + Arrays.toString(args)); } }MyCommandLineRunner2@Component @Order(1) @Slf4j public class MyCommandLineRunner2 implements CommandLineRunner { @Override public void run(String... args) { log.info("Runner2>>>" + Arrays.toString(args)); } }idea配置入口参数@Order(1)用来描述CommandLineRunner的执行顺序,值越小越先执行。run()方法的参数是系统启动时传入的参数。
2021年06月08日
1,038 阅读
0 评论
0 点赞
2021-06-07
Spring Boot注册拦截器Interceptor
Spring MVC提供了AOP风格的拦截器,拥有更加精细的拦截器处理能力。Spring Boot中拦截器的注册更加方便,步骤如下:spring-boot-starter-web创建拦截器,实现HandlerInterceptor配置拦截器,定义配置类进行拦截器的配置增加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>实现HandlerInterceptor代码如下:public class MyInterceptor implements HandlerInterceptor { private final Logger logger = LoggerFactory.getLogger(MyInterceptor.class); /** * 方法执行前运行 * 必须返回true,后面的方法才能执行 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { logger.info("我先执行"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { logger.info("我在controller方法之后执行"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.info("我最后执行"); } }配置拦截器@Configuration public class MyWebMvcConfig implements WebMvcConfigurer { /** * 拦截器 * * @param registry registry */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()) //配置拦截的路由 .addPathPatterns("/interceptor/**") //配置不拦截的路由 .excludePathPatterns("/demo/**") //配置顺序 .order(1); } }测试定义controller测试我们的拦截器@RestController @RequestMapping("interceptor") public class InterceptorController { private final Logger logger = LoggerFactory.getLogger(InterceptorController.class); @GetMapping("/test") public String testInterceptor(){ logger.info("我是controller方法"); return "success"; } }通过调用http://localhost:8080/interceptor/test查看输出日志。[line]温馨提示[/line]拦截器按照preHandle→Controller→postHandle→afterHandle的顺序执行。只有preHandle方法返回true时,后面的方法才会执行。当拦截器链内存在多个拦截器时,postHandle在拦截器链内所有拦截器返回成功时才会调用。当拦截器链内存在多个拦截器时,afterHandle在拦截器链内所有拦截器返回true时才会调用。当拦截器链内存在多个拦截器时,如果第一个拦截器的preHandle方法返回false,则后面的方法都不会执行。调用controller方法时,只要配置了拦截的路由,哪怕前端请求404,仍然会调用preHandle、postHandle及afterHandle的方法。如果我们设置了order,代码如下:/** * 拦截器 * * @param registry registry */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor2()) //配置拦截的路由 .addPathPatterns("/interceptor/**") //配置不拦截的路由 .excludePathPatterns("/demo/**") //配置顺序 .order(200); registry.addInterceptor(new MyInterceptor1()) //配置拦截的路由 .addPathPatterns("/interceptor/**") //配置不拦截的路由 .excludePathPatterns("/demo/**") //配置顺序 .order(300); }
2021年06月07日
1,168 阅读
1 评论
1 点赞
2021-06-07
springboot 通过 DefaultErrorAttributes自定义错误信息
自定义error数据就是对返回的数据进行自定义。Spring Boot返回的Error信息一共有5条,分别是timestamp、status、error、path。在BasicErrorController的errorHtml()方法和error()方法,都是通过getErrorAttributes()方法获取Error信息的,该方法最终会调用DefaultErrorAttributes类的getErrorAttributes()方法,而DefaultErrorAttributes类是在ErrorMvcAutoConfiguration中默认提供的。当系统没有提供 errorAttributes 时才会采 DefaultErrorAttributes,因此自定义错误提示时,只需要自己提供一个ErrorAttributes即可,而DefaultErrorAttributes是ErrorAttributes的子类,因此只需要继承 DefaultErrorAttributes 即可。@Component public class MyErrorAttribute extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { Map<String, Object> map = super.getErrorAttributes(webRequest, options); map.put("errorMsg", "出错了"); return map; } }
2021年06月07日
2,088 阅读
0 评论
1 点赞
2021-06-06
SpringBoot 使用Gson
添加依赖需要排除web自带的jackson <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency>增加配置文件@Configuration public class GsonConfig { @Bean @ConditionalOnMissingBean public GsonHttpMessageConverter gsonHttpMessageConverter() { GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(); gsonHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8); GsonBuilder gsonBuilder = new GsonBuilder(); //设置日期格式 gsonBuilder.setDateFormat("yyyy-MM-dd"); //设置忽略的字段 gsonBuilder.excludeFieldsWithModifiers(Modifier.PROTECTED); Gson gson = gsonBuilder.create(); gsonHttpMessageConverter.setGson(gson); return gsonHttpMessageConverter; } }增加测试类@Data public class Person { protected Integer age; private String name; private Date birthday; }测试 @GetMapping("test") public Person test() { Person person = new Person(); person.setAge(30); person.setBirthday(new Date()); person.setName("张三"); return person; }
2021年06月06日
1,139 阅读
0 评论
0 点赞
1
...
4
5
6
...
9