欢迎来到Heck's Blog,专业承接拿站、企业建站、仿站、网上商城架构、门户网站搭建、空间域名注册、软件定制等项目。关注网络安全,因为专注,所以专业,懂得放弃,才能收获。有事请发邮件至i@heckjj.com,请记住本站网址:http://www.heckjj.com,多谢。
7月3
5月16
我正在使用旧版Spring应用程序,并且想要迁移到Spring Boot。我的意图是使用spring-boot-starter-data- jpa。因此,我在pom.xml(管理所有spring-boot-dependencies)中添加了以下部分:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
但这搞砸了我暂时需要保留的某些依赖项。我目前正在使用Selenium依赖项(版本2.53.0;从另一个项目中过渡添加),但是spring-
boot正在获取的依赖项3.9.1。
我想排除3.9.1依赖关系,但exclusion过滤器无法按预期工作。
不能乱<excludes>然后尝试弄清楚您需要再次包含什么(在弄清楚要排除的内容之后)。只需覆盖《Spring
Boot参考指南》中此处解释的版本即可。
假设您将spring-boot-starter- parent用作父项,则只需将a添加<selenium.version>到您的<properties>部分中即可指定所需的版本。
<properties>
<selenium.version>2.53.0</selenium.version>
</properties>
这将使Spring Boot使用所需的版本。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
但这搞砸了我暂时需要保留的某些依赖项。我目前正在使用Selenium依赖项(版本2.53.0;从另一个项目中过渡添加),但是spring-
boot正在获取的依赖项3.9.1。
我想排除3.9.1依赖关系,但exclusion过滤器无法按预期工作。
不能乱<excludes>然后尝试弄清楚您需要再次包含什么(在弄清楚要排除的内容之后)。只需覆盖《Spring
Boot参考指南》中此处解释的版本即可。
假设您将spring-boot-starter- parent用作父项,则只需将a添加<selenium.version>到您的<properties>部分中即可指定所需的版本。
<properties>
<selenium.version>2.53.0</selenium.version>
</properties>
这将使Spring Boot使用所需的版本。
3月12
IDEA的Service窗口误删服务(也就是点到了Hide Configuration选项)后如何恢复
看下到底是做了什么操作导致的服务被隐藏 (赶时间直接到最后看解决方案就行)
正常情况下, 在开启窗口的情况下, 会显示我们所有的微服务启动类, 如下图
idea在service窗口中显示多个服务如下:在这里插入图片描述
.idea > workspace.xml 中找到 RunDashboard 替换成如下
<component name="RunDashboard">
<option name="configurationTypes">
<set>
<option value="SpringBootApplicationConfigurationType" />
</set>
</option>
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
看下到底是做了什么操作导致的服务被隐藏 (赶时间直接到最后看解决方案就行)
正常情况下, 在开启窗口的情况下, 会显示我们所有的微服务启动类, 如下图
idea在service窗口中显示多个服务如下:在这里插入图片描述
.idea > workspace.xml 中找到 RunDashboard 替换成如下
<component name="RunDashboard">
<option name="configurationTypes">
<set>
<option value="SpringBootApplicationConfigurationType" />
</set>
</option>
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
1月2
在SpringBoot中使用单元测试时,出现以下报错,意思是创建名为‘serverEndpointExporter’的bean时出错。
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
[20240102 14:42:43][main][ERROR][org.springframework.boot.SpringApplication:854] Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverEndpointExporter' defined in class path resource [com/nine/rivers/bms/system/config/WebSocketConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:765)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:445)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:121)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:350)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:355)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$7(ClassBasedTestDescriptor.java:350)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743)
at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:349)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$4(ClassBasedTestDescriptor.java:270)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:269)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:259)
at java.util.Optional.orElseGet(Optional.java:267)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:258)
at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:101)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:100)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:111)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:111)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
at java.util.ArrayList.forEach(ArrayList.java:1259)
问题分析
通过报错提示可以看出,在创建命名为 ‘serverEndpointExporter’ 的bean时出错,而这个bean是webscoket中的,而webscoket是需要依赖tomcat等容器才能启动的,恰巧运行单元测试不需要依赖tomcat容器,两者互相矛盾这就是出现该问题的原因了。
问题解决
使用tomcat容器运行单元测试,在注解 @SpringbootTest 中追加以下内容即可:
@SpringbootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
[20240102 14:42:43][main][ERROR][org.springframework.boot.SpringApplication:854] Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverEndpointExporter' defined in class path resource [com/nine/rivers/bms/system/config/WebSocketConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:765)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:445)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:121)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:350)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:355)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$7(ClassBasedTestDescriptor.java:350)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743)
at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:349)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$4(ClassBasedTestDescriptor.java:270)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:269)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:259)
at java.util.Optional.orElseGet(Optional.java:267)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:258)
at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:101)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:100)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:111)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:111)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
at java.util.ArrayList.forEach(ArrayList.java:1259)
问题分析
通过报错提示可以看出,在创建命名为 ‘serverEndpointExporter’ 的bean时出错,而这个bean是webscoket中的,而webscoket是需要依赖tomcat等容器才能启动的,恰巧运行单元测试不需要依赖tomcat容器,两者互相矛盾这就是出现该问题的原因了。
问题解决
使用tomcat容器运行单元测试,在注解 @SpringbootTest 中追加以下内容即可:
@SpringbootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
12月25
前后端通过websocket通信,但是需要鉴权,可以利用websocket的子协议来传输token,代码如下:
var ws = new WebSocket("ws://localhost/ws",[token]);
在后面加上[这里是token内容]。这样请求头就会携带:
Sec-WebSocket-Protocol:token value
参数是一个数组。如果数组有多个值,后端也会接受到逗号隔开的值。
后端可以获取这个token进行鉴权。
重点来了!
如果传递了token参数,后端响应的时候,也必须带上这个token响应!否则前端接收不到数据!
我竟然忘记前端传过来的token是加密后的,首先解密后去校验,通过后再把原加密token放在响应头即可, 如果不一致也会导致前端接收不到消息。
如下是java的例子“:
HttpServletResponse response = (HttpServletResponse)servletResponse;
response.setHeader("Sec-WebSocket-Protocol", token);
var ws = new WebSocket("ws://localhost/ws",[token]);
在后面加上[这里是token内容]。这样请求头就会携带:
Sec-WebSocket-Protocol:token value
参数是一个数组。如果数组有多个值,后端也会接受到逗号隔开的值。
后端可以获取这个token进行鉴权。
重点来了!
如果传递了token参数,后端响应的时候,也必须带上这个token响应!否则前端接收不到数据!
我竟然忘记前端传过来的token是加密后的,首先解密后去校验,通过后再把原加密token放在响应头即可, 如果不一致也会导致前端接收不到消息。
如下是java的例子“:
HttpServletResponse response = (HttpServletResponse)servletResponse;
response.setHeader("Sec-WebSocket-Protocol", token);
12月21
什么是实时主备?
实时主备由一个主库以及一个或者多个配置了实时(Realtime)归档的备库组成,其主要目的是保障数据库可用性,提高数据安全性。实时主备系统中,主库提供完整的数据库功能,备库提供只读服务。主库修改数据产生的Redo日志,通过实时归档机制,在写入联机Redo日志文件之前发送到备库,实时备库通过重演Redo日志与主库保持数据同步。当主库出现故障时,备库在将所有Redo日志重演结束后,就可以切换为主库对外提供数据库服务
1、环境准备
服务器 主库IP:192.168.90.41 dm8数据库 实例名 :RAC1 端口号:5236
服务器 备库IP:192.168.90.42 dm8数据库 实例名 :RAC2 端口号:5236
# 数据库启动服务命令路径/dm8/bin,实例配置文件路径/dm8/data/DAMENG/
2、主备库分别初始化实例(按客户要求)
./dminit path=/dm8/data page_size=32 instance_name=RAC1
./dminit path=/dm8/data page_size=32 instance_name=RAC2
3 备份还原
# 如果是初始搭建环境,可以通过对主库脱机备份、对备库脱机还原的方式来准备数据, 如果主库已经处于运行状态,则可以对主库进行联机备份、对备库脱机还原的方式来准备数据。
实时主备由一个主库以及一个或者多个配置了实时(Realtime)归档的备库组成,其主要目的是保障数据库可用性,提高数据安全性。实时主备系统中,主库提供完整的数据库功能,备库提供只读服务。主库修改数据产生的Redo日志,通过实时归档机制,在写入联机Redo日志文件之前发送到备库,实时备库通过重演Redo日志与主库保持数据同步。当主库出现故障时,备库在将所有Redo日志重演结束后,就可以切换为主库对外提供数据库服务
1、环境准备
服务器 主库IP:192.168.90.41 dm8数据库 实例名 :RAC1 端口号:5236
服务器 备库IP:192.168.90.42 dm8数据库 实例名 :RAC2 端口号:5236
# 数据库启动服务命令路径/dm8/bin,实例配置文件路径/dm8/data/DAMENG/
2、主备库分别初始化实例(按客户要求)
./dminit path=/dm8/data page_size=32 instance_name=RAC1
./dminit path=/dm8/data page_size=32 instance_name=RAC2
3 备份还原
# 如果是初始搭建环境,可以通过对主库脱机备份、对备库脱机还原的方式来准备数据, 如果主库已经处于运行状态,则可以对主库进行联机备份、对备库脱机还原的方式来准备数据。
12月19
咱话不多说,正如标题所见,实践开始。
首先打开cmd,win键+r打开运行,输入cmd打开控制台。
在控制台中输入msg / server:IP地址 * "要发送的内容。" 注:(这里的引号要加,且*号左右必须空一格)
例如:我的ipv4地址是192.168.90.1** 注:(用ipconfig命令可查)
首先打开cmd,win键+r打开运行,输入cmd打开控制台。
在控制台中输入msg / server:IP地址 * "要发送的内容。" 注:(这里的引号要加,且*号左右必须空一格)
例如:我的ipv4地址是192.168.90.1** 注:(用ipconfig命令可查)
12月14
一. 相同之处
都是为了解决人的需求,都需要去深入挖掘目标用户的需求,进行分析转化为功能,利用最低的成本去满足用户最迫切的需求。
都需要把产品做好,用户用得爽,才能实现盈利。
产品经理和销售经理都需要具备核心能力(包括:需求分析、产品管理、项目管理、沟通能力、技术能力、业务能力、产品设计、学习能力、逻辑思维等)。
二、不同之处
(1)产品定位:
To C需从产品能给人们解决哪些问题的角度去考虑产品定位;
To B是结合商业公司内部使用需要的层面去考虑;B端产品一定要在企业的利润链上产生价值,对企业的利润产生贡献。对最终的利润正向贡献越大,产品的价值也就越大。
To G则是从国家政策、政府工作报告等体现要做什么样的产品(比如:通过“数字政府”营造粤港澳大湾区营商与政务环境)。产品定位决定了目前用户、场景、需求等一系列维度。
(2)用户定位:To C面向个人用户;To B面向企业;To G面向政府(使用用户可以为政府决策人员、普通大众、行业用户)。
(3)需求场景:To C使用场地是随时对地;To B更多是内网;To G是内外网相结合(互联网+政务)。
(4)产品模式:商业模式或者市场路线。To C需要进行用户调研寻找细分用户,通过市场调研挖掘本职需求,需要更多地思考产品设计和用户体验层次的问题;To B和To G则需要对客户进行深度沟通,寻找MVP,而且需要一套能说服客户又能寻求利益最大化的定价策略。
(5)用户需求:To C要结合用户的“人性”需要,去挖掘大多数用户的可能性,需要做各种各样的竞品分析(包括同类产品功能层面和不同类产品解决方案);To B也是找寻大多数企业的共性需求,除非是定制化需求;To G这种则是通过一个个项目形式去满足不同时期政策的需要和符合财政预算,这类需求需要通过政府客户获取。
(6)盈利模式:To C通过内容吸引用户,有了用户流,带动资金流、物流,每个用户都是盈利的来演;To B和To G走的都是项目合同制,可以分为一期、二期和n期,需要不断保持与客户的合作关系,进行迭代规划,才能实现产品的持续变现。
(7)MVP思路不同:
建设B端和C端产品时,大的原则是类似的,都是先做加法,即充分讨论、穷举所有需求和可能性;然后再做减法,选出最核心的需求点;最后设计具体方案并将其落地,用最短的时 间和最低的成本支持业务启动。
但是在选取最小功能集合(或最小可行产品)时,B端和C端产品的区别很大:
B端产品要支持业务整体运作,所以在选取最小功能集合时,即便再简化,也要保证一个核心业务流程的运转,因此B端MVP往往是一个具备一定复杂度的系统,不可能是一个或几个功能点。
C端产品需要解决用户的痛点,需要挑选一个核心痛点去打动用户,如果核心痛点定位错误,就会导致验证失败。所以在选取最小功能集合时,C端产品要聚焦用户的核心痛 点,C端MVP可能只包含一两个功能点。
都是为了解决人的需求,都需要去深入挖掘目标用户的需求,进行分析转化为功能,利用最低的成本去满足用户最迫切的需求。
都需要把产品做好,用户用得爽,才能实现盈利。
产品经理和销售经理都需要具备核心能力(包括:需求分析、产品管理、项目管理、沟通能力、技术能力、业务能力、产品设计、学习能力、逻辑思维等)。
二、不同之处
(1)产品定位:
To C需从产品能给人们解决哪些问题的角度去考虑产品定位;
To B是结合商业公司内部使用需要的层面去考虑;B端产品一定要在企业的利润链上产生价值,对企业的利润产生贡献。对最终的利润正向贡献越大,产品的价值也就越大。
To G则是从国家政策、政府工作报告等体现要做什么样的产品(比如:通过“数字政府”营造粤港澳大湾区营商与政务环境)。产品定位决定了目前用户、场景、需求等一系列维度。
(2)用户定位:To C面向个人用户;To B面向企业;To G面向政府(使用用户可以为政府决策人员、普通大众、行业用户)。
(3)需求场景:To C使用场地是随时对地;To B更多是内网;To G是内外网相结合(互联网+政务)。
(4)产品模式:商业模式或者市场路线。To C需要进行用户调研寻找细分用户,通过市场调研挖掘本职需求,需要更多地思考产品设计和用户体验层次的问题;To B和To G则需要对客户进行深度沟通,寻找MVP,而且需要一套能说服客户又能寻求利益最大化的定价策略。
(5)用户需求:To C要结合用户的“人性”需要,去挖掘大多数用户的可能性,需要做各种各样的竞品分析(包括同类产品功能层面和不同类产品解决方案);To B也是找寻大多数企业的共性需求,除非是定制化需求;To G这种则是通过一个个项目形式去满足不同时期政策的需要和符合财政预算,这类需求需要通过政府客户获取。
(6)盈利模式:To C通过内容吸引用户,有了用户流,带动资金流、物流,每个用户都是盈利的来演;To B和To G走的都是项目合同制,可以分为一期、二期和n期,需要不断保持与客户的合作关系,进行迭代规划,才能实现产品的持续变现。
(7)MVP思路不同:
建设B端和C端产品时,大的原则是类似的,都是先做加法,即充分讨论、穷举所有需求和可能性;然后再做减法,选出最核心的需求点;最后设计具体方案并将其落地,用最短的时 间和最低的成本支持业务启动。
但是在选取最小功能集合(或最小可行产品)时,B端和C端产品的区别很大:
B端产品要支持业务整体运作,所以在选取最小功能集合时,即便再简化,也要保证一个核心业务流程的运转,因此B端MVP往往是一个具备一定复杂度的系统,不可能是一个或几个功能点。
C端产品需要解决用户的痛点,需要挑选一个核心痛点去打动用户,如果核心痛点定位错误,就会导致验证失败。所以在选取最小功能集合时,C端产品要聚焦用户的核心痛 点,C端MVP可能只包含一两个功能点。
11月23
用 security加redis写项目时一直报这个错误,说是没有set方法?我用的data注解怎么可能
这个bug找了一下午,终于找到原因了:redis序列化会查询所有以get和set开头的方法,而我的user继承了security的UserDetails,多了一个集合类型的getAuthorities方法,所有导致无法序列化,使用的是jackson的序列化器
解决办法:
加上@JsonIgnore注解设置不序列化
@JsonIgnore
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
ArrayList<NdpAuthority> grantedAuthorities = CollectionUtil.newArrayList();
if (ObjUtil.isNotEmpty(roles)) {
roles.forEach(dict -> {
String roleName = dict.getStr(CommonConstant.NAME);
NdpAuthority ndpAuthority = new NdpAuthority(roleName);
grantedAuthorities.add(ndpAuthority);
});
}
return grantedAuthorities;
}
加个属性,写个对应的set方法
这个bug找了一下午,终于找到原因了:redis序列化会查询所有以get和set开头的方法,而我的user继承了security的UserDetails,多了一个集合类型的getAuthorities方法,所有导致无法序列化,使用的是jackson的序列化器
解决办法:
加上@JsonIgnore注解设置不序列化
@JsonIgnore
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
ArrayList<NdpAuthority> grantedAuthorities = CollectionUtil.newArrayList();
if (ObjUtil.isNotEmpty(roles)) {
roles.forEach(dict -> {
String roleName = dict.getStr(CommonConstant.NAME);
NdpAuthority ndpAuthority = new NdpAuthority(roleName);
grantedAuthorities.add(ndpAuthority);
});
}
return grantedAuthorities;
}
加个属性,写个对应的set方法
11月23
在实际项目开发过程中,我们有时候需要让项目在启动时执行特定方法。如要实现这些功能:
提前加载相应的数据到缓存中;
检查当前项目运行环境;
检查程序授权信息,若未授权则不能使用后续功能;
执行某个特定方法;
一直想整理一下Springboot启动后自执行某段代码或者方法相关的点,囿于时间问题及担心理解不是太全面所以没整理,后来一想先整理出来,将这一方面的东西记录下来。其实这篇文章不应该体现spring boot,因为自动执行方式不仅限于spring boot,java spring细化到bean的初始化都可以完成。
一、java自身的启动时加载方式
1、static代码块
static静态代码块,在类加载的时候即自动执行。 由于静态代码块没有名字,我们并不能主动调用,它会在类加载的时候,自动执行。所以静态代码块,可以更早的给类中的静态属性,进行初始化赋值操作。并且,静态代码块只会自动被执行一次,因为JVM在一次运行中,对一个类只会加载一次!
2、构造函数constructor
在对象初始化时执行。执行顺序在static静态代码块之后。
3、@PostConstruct注解
@PostConstruct
public void testInit() {
System.out.printin("postConstruct“);
}
@PostConstruct注解使用在方法上,这个方法在对象依赖注入初始化之后执行。执行节点在BeanPostProcessor的postProcessBeforeInitialization之后,在postProcessAfterInitialization之前。
很多人以为该注解是Spring提供的。其实是Java自己的注解。Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
注意:加了postconstruct注解的方法,如果执行失败,整个程序会无法正常启动!这个方法执行不完,整个程序也启动不了!也不建议将耗时逻辑放到这里面来。
二、Servlet加载的方式
1、实现ServletContextListener接口contextInitialized方法
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@Slf4j
@Component
public class ServletContextListenerImpl implements ServletContextListener {
/**
* 在初始化Web应用程序中的任何过滤器或Servlet之前,将通知所有ServletContextListener上下文初始化。
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("启动时自动执行 ServletContextListener 的 contextInitialized 方法");
}
}
注意:该方法会在填充完普通Bean的属性,但是还没有进行Bean的初始化之前执行
三、Spring启动时加载方式
1、实现ServletContextAware接口setServletContext 方法
@Component
public class StartInitServletContext implements ServletContextAware {
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("StartInitServletContext: 开始处理事情");
}
}
2、ApplicationListener监听器
创建Listener的方式有两种:
方式1:编程实现ApplicationListener接口
方式2:使用@EventListener注解
注意监听的事件,通常是ApplicationStartedEvent 或者ApplicationReadyEvent,其他的事件可能无法注入bean。
编程实现ApplicationListener接口
/**
* 监听的是 ApplicationStartedEvent 事件,
* 则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之前执行;
*/
@Component
public class StartInitStartedEvent implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("StartInitStartedEvent:开始处理事情");
}
}
/**
* 监听的是 ApplicationReadyEvent 事件,
* 则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之后执行;
*/
@Component
public class StartInitReadyEvent implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("StartInitReadyEvent: 开始处理事情");
}
}
实现 public interface ApplicationListener<E extends ApplicationEvent> 接口,监听 ApplicationEvent 及其下面的子事件:
/**
* 事件监听器一般是由开发者自己定义
* 定义事件监听器
*/
@Component
//@Lazy
public class MyApplicationListener implements ApplicationListener{
@Override
public void onApplicationEvent(ApplicationEvent event) {
event = (PayloadApplicationEvent)event;
System.out.println(((PayloadApplicationEvent<?>) event).getPayload());
}
}
@EventListener方式
将要执行的方法所在的类交个Spring容器扫描(@Component),并且在要执行的方法上添加@EventListener注解执行
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class EventListenerTest {
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("启动时自动执行 @EventListener 注解方法");
}
}
3、InitializingBean接口
@Component
@Data
public class TestInit implements InitializingBean,eanFactoryAware,ApplicationContextAware{
private BeanFactory beanFactory:
private ApplicationContext applicationContext;
private String name;
@Override
public voidafterPropertiesSet(hrows Exception {
System.out.printin("InIt heck");
}
}
Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。
实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。先调用afterPropertieSet()方法,然后再调用init-method中指定的方法。
4、ApplicationRunner和CommandLineRunner
SpringBoot提供了两个接口来实现Spring容器启动完成后执行的功能,两个接口分别为CommandLineRunner和ApplicationRunner。这两个接口需要实现一个run方法,将代码在run中实现即可。这两个接口功能基本一致,其区别在于run方法的入参。ApplicationRunner的run方法入参为ApplicationArguments,为CommandLineRunner的run方法入参为String数组。
提前加载相应的数据到缓存中;
检查当前项目运行环境;
检查程序授权信息,若未授权则不能使用后续功能;
执行某个特定方法;
一直想整理一下Springboot启动后自执行某段代码或者方法相关的点,囿于时间问题及担心理解不是太全面所以没整理,后来一想先整理出来,将这一方面的东西记录下来。其实这篇文章不应该体现spring boot,因为自动执行方式不仅限于spring boot,java spring细化到bean的初始化都可以完成。
一、java自身的启动时加载方式
1、static代码块
static静态代码块,在类加载的时候即自动执行。 由于静态代码块没有名字,我们并不能主动调用,它会在类加载的时候,自动执行。所以静态代码块,可以更早的给类中的静态属性,进行初始化赋值操作。并且,静态代码块只会自动被执行一次,因为JVM在一次运行中,对一个类只会加载一次!
2、构造函数constructor
在对象初始化时执行。执行顺序在static静态代码块之后。
3、@PostConstruct注解
@PostConstruct
public void testInit() {
System.out.printin("postConstruct“);
}
@PostConstruct注解使用在方法上,这个方法在对象依赖注入初始化之后执行。执行节点在BeanPostProcessor的postProcessBeforeInitialization之后,在postProcessAfterInitialization之前。
很多人以为该注解是Spring提供的。其实是Java自己的注解。Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
注意:加了postconstruct注解的方法,如果执行失败,整个程序会无法正常启动!这个方法执行不完,整个程序也启动不了!也不建议将耗时逻辑放到这里面来。
二、Servlet加载的方式
1、实现ServletContextListener接口contextInitialized方法
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@Slf4j
@Component
public class ServletContextListenerImpl implements ServletContextListener {
/**
* 在初始化Web应用程序中的任何过滤器或Servlet之前,将通知所有ServletContextListener上下文初始化。
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("启动时自动执行 ServletContextListener 的 contextInitialized 方法");
}
}
注意:该方法会在填充完普通Bean的属性,但是还没有进行Bean的初始化之前执行
三、Spring启动时加载方式
1、实现ServletContextAware接口setServletContext 方法
@Component
public class StartInitServletContext implements ServletContextAware {
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("StartInitServletContext: 开始处理事情");
}
}
2、ApplicationListener监听器
创建Listener的方式有两种:
方式1:编程实现ApplicationListener接口
方式2:使用@EventListener注解
注意监听的事件,通常是ApplicationStartedEvent 或者ApplicationReadyEvent,其他的事件可能无法注入bean。
编程实现ApplicationListener接口
/**
* 监听的是 ApplicationStartedEvent 事件,
* 则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之前执行;
*/
@Component
public class StartInitStartedEvent implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("StartInitStartedEvent:开始处理事情");
}
}
/**
* 监听的是 ApplicationReadyEvent 事件,
* 则 ApplicationListener 一定会在 CommandLineRunner 和 ApplicationRunner 之后执行;
*/
@Component
public class StartInitReadyEvent implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("StartInitReadyEvent: 开始处理事情");
}
}
实现 public interface ApplicationListener<E extends ApplicationEvent> 接口,监听 ApplicationEvent 及其下面的子事件:
/**
* 事件监听器一般是由开发者自己定义
* 定义事件监听器
*/
@Component
//@Lazy
public class MyApplicationListener implements ApplicationListener{
@Override
public void onApplicationEvent(ApplicationEvent event) {
event = (PayloadApplicationEvent)event;
System.out.println(((PayloadApplicationEvent<?>) event).getPayload());
}
}
@EventListener方式
将要执行的方法所在的类交个Spring容器扫描(@Component),并且在要执行的方法上添加@EventListener注解执行
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class EventListenerTest {
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("启动时自动执行 @EventListener 注解方法");
}
}
3、InitializingBean接口
@Component
@Data
public class TestInit implements InitializingBean,eanFactoryAware,ApplicationContextAware{
private BeanFactory beanFactory:
private ApplicationContext applicationContext;
private String name;
@Override
public voidafterPropertiesSet(hrows Exception {
System.out.printin("InIt heck");
}
}
Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。
实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。先调用afterPropertieSet()方法,然后再调用init-method中指定的方法。
4、ApplicationRunner和CommandLineRunner
SpringBoot提供了两个接口来实现Spring容器启动完成后执行的功能,两个接口分别为CommandLineRunner和ApplicationRunner。这两个接口需要实现一个run方法,将代码在run中实现即可。这两个接口功能基本一致,其区别在于run方法的入参。ApplicationRunner的run方法入参为ApplicationArguments,为CommandLineRunner的run方法入参为String数组。