开心一笑
【坐在沙发上看电视,女友洗完澡出来蛮开心的问我,亲爱的:为什么洗完澡总觉得自己漂亮了好多?我问她:你洗澡的时候洗了头吧?她说:是啊!我回答说:那肯定是脑子进水了…刚说完这句我就后悔了,看着女票的脸色,我想静静…】
提出问题
SpringBoot整合其它技术大合集???
学习地址
CSDN学习地址:
51CTO学习地址:http://edu.51cto.com/lecturer/5592452.html
解决问题
前言
本篇文章是《一步一步学SpringBoot(二)》教学视频的简单课件,内容不是很详细,想了解全部内容,可以到上面的视频地址观看学习。
Spring Boot拦截器Interceptor
1)Spring boot拦截器默认
- HandlerInterceptorAdapter
- AbstractHandlerMapping
- UserRoleAuthorizationInterceptor
- LocaleChangeInterceptor
- ThemeChangeInterceptor
preHandle****:**预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现);
返回值:true表示继续流程(如调用下一个拦截器或处理器);
false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
postHandle****:**后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
afterCompletion****:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
2)配置spring mvc的拦截器WebMvcConfigurerAdapter
public class WebAppConfig extends WebMvcConfigurerAdapter
具体类如下:
package com.example.interceptor.test;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Created by Ay on 2017/8/23.
*/
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserSecurityInterceptor()).addPathPatterns("/springdata/*");
}
}
3)实现添加拦截器方法
public void addInterceptors(InterceptorRegistry registry){
}
registry.addInterceptor可以通过此方法添加拦截器, 可以是spring提供的或者自己添加的
具体类如下:
package com.example.interceptor.test;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by Ay on 2017/8/23.
*/
public class UserSecurityInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
//业务处理
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
//业务处理
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)throws Exception {
//业务处理
System.out.println("afterCompletion");
}
}
4)定义控制层进行测试
具体类如下:
package com.example.interceptor.test;
import io.swagger.annotations.ApiOperation;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Ay
* @date 2017/1/24.
*/
@RestController
@RequestMapping(value="/springdata")
@EnableAutoConfiguration
@EnableScheduling
public class AyInterceptorsTestController {
@RequestMapping("/ay")
@ApiOperation(value = "ay",httpMethod ="GET", response = String.class,notes = "index")
public String index(){
return "Hello Ay...";
}
@RequestMapping("/test")
@ApiOperation(value = "test",httpMethod ="GET", response = String.class,notes = "index")
public String test(){
return "Hello Ay...";
}
}
Spring Boot集成MongoDB
假如你已经安装好了mongoDB数据库,并新建了一个test数据库。那么开始吧
1)pom文件添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2)创建实体
package com.example.mongodb.test;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.persistence.Id;
/**
* 描述:
* @author Ay
* @date 2017/08/22
*/
@Document
public class AyTest {
@Id
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3)服务层
package com.example.mongodb.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Created by Ay on 2017/8/23.
*/
@Component
public class UserDaoImpl {
@Autowired
private MongoTemplate mongoTemplate;
public void save(){
AyTest ayTest = new AyTest();
ayTest.setId("2");
ayTest.setName("al");
mongoTemplate.save(ayTest);
}
}
4)application.properties添加配置
###mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=test
5)测试
package com.example.mongodb.test;
import com.example.intellij.test.AyTest;
import com.example.intellij.test.AyTestService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by Ay on 2017/1/24.
*/
@RestController
@RequestMapping("/mongo")
public class MongoDBTestController {
@Autowired
private UserDaoImpl userDaoImpl;
@RequestMapping("/al")
public String index2(){
userDaoImpl.save();
return "Hello Ay...";
}
}
Spring Boot多环境配置
一. 多环境配置的好处:
1.不同环境配置可以配置不同的参数~
2.便于部署,提高效率,减少出错~
二. properties多环境配置
- 配置激活选项
spring.profiles.active=dev ### 代表使用开发环境
2.添加其他配置文件
application.properties:
#激活哪一个环境的配置文件
spring.profiles.active=dev
Spring Boot集成Log4J
1)添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 排查默认日志包 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入log4j2依赖 start-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- 引入log4j2依赖 end-->
2)application.properties添加
logging.config=classpath:log4j2.xml
3)resources文件夹下添加文件 log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
4)测试下
package com.example.log4j2.test;
import com.example.intellij.test.AyTestService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by Ay on 2017/1/24.
*/
@RestController
@RequestMapping("/log4j2")
public class Log4JTestController {
@Autowired
private AyTestService ayTestService;
Logger logger = LogManager.getLogger(this.getClass());
@RequestMapping("/al")
public String index2(){
logger.info("method start");
logger.equals("method start");
return "Hello Ay...";
}
}
Spring Boot事务控制
在Spring Boot中,当我们使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依赖的时候,框 架会自动默认分别注入DataSourceTransactionManager或JpaTransactionManager。所以我们不需要任何额外 配置就可以用@Transactional注解进行事务的使用。
1)主要是@Transactional这个注解的使用
package com.example.transaction.test;
import com.example.intellij.test.AyTest;
import com.example.intellij.test.AyTestService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by Ay on 2017/1/24.
*/
@RestController
@RequestMapping("/transaction")
public class TransactionTestController {
@Autowired
private AyTestService ayTestService;
@RequestMapping("/ay")
@Transactional
public String index() {
AyTest ayTest = new AyTest();
ayTest.setId("1");
ayTest.setName("ay");
AyTest ayTest2 = new AyTest();
ayTest2.setId("2");
ayTest2.setName("al & ay");
AyTest ayTest3 = new AyTest();
ayTest3.setId("3");
ayTest3.setName("al");
ayTestService.insert(ayTest);
ayTestService.insert(ayTest2);
//这边出现异常
String s = null;
s.split(",");
ayTestService.insert(ayTest3);
return "Hello Ay...";
}
}
Spring Boot自定义错误页面
1)在resources/static文件夹下新建3个文件:401.html,404.html,500.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
我是一个漂亮的401
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
我是一个漂亮的404
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
我是一个漂亮的500
</body>
</html>
2)开发配置类
package com.example.errorpage.test;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
/**
* Created by Ay on 2017/8/23.
*/
@Configuration
public class ErrorPageConfig {
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/401.html");
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html");
container.addErrorPages(error401Page, error404Page, error500Page);
}
};
}
}
Spring Boot运用打包发布
略,可看我录制的《一步一步学SpringBoot(二)》教学视频
Spring Boot使用Druid
Druid是Java语言中最好的数据库连接池,并且能够提供强大的监控和扩展功能。
第一步:添加依赖
<!-- druid start -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.18</version>
</dependency>
<!-- druid end -->
第二步:配置数据源相关信息
#mysql配置信息
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test2
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
#spring.datasource.useGlobalDataSourceStat=true
第三步:配置监控统计功能
package com.example.druid.test;
import com.alibaba.druid.support.http.WebStatFilter;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
/**
* druid过滤器.
* @author Administrator
*
*/
@WebFilter(filterName="druidWebStatFilter",urlPatterns="/*",
initParams={
@WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略资源
}
)
public class DruidStatFilter extends WebStatFilter {
}
package com.example.druid.test;
import com.alibaba.druid.support.http.StatViewServlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
/**
* druid数据源状态监控.
* @author Administrator
*
*/
@WebServlet(urlPatterns="/druid/*",
initParams={
@WebInitParam(name="allow",value="192.168.1.72,127.0.0.1"),// IP白名单 (没有配置或者为空,则允许所有访问)
@WebInitParam(name="deny",value="192.168.1.73"),// IP黑名单 (存在共同时,deny优先于allow)
@WebInitParam(name="loginUsername",value="admin"),// 用户名
@WebInitParam(name="loginPassword",value="123456"),// 密码
@WebInitParam(name="resetEnable",value="false")// 禁用HTML页面上的“Reset All”功能
}
)
public class DruidStatViewServlet extends StatViewServlet {
private static final long serialVersionUID = 1L;
}
Spring Boot 使用Retry重试
1)引入pom文件
<!-- spring-retry start -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- spring-retry start -->
2)自定义一个简单异常
package com.example.retry.test;
/**
* Created by Ay on 2017/8/22.
*/
public class BusinessException extends Exception{
}
3)服务类
package com.example.retry.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
@Component("remoteService")
public class RemoteService {
private static final Logger logger = LoggerFactory.getLogger(RemoteService.class);
@Retryable(value= {BusinessException.class},maxAttempts = 5,backoff = @Backoff(delay = 5000,multiplier = 2))
public void call() throws Exception {
logger.info("do something...");
throw new BusinessException();
}
@Recover
public void recover(BusinessException e) {
//具体的业务逻辑
logger.info(" --------------------------- ");
logger.info(e.getMessage());
}
}
4)测试类
package com.example.retry.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/retry")
public class TestController {
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
@Autowired
private RemoteService remoteService;
@RequestMapping("/test")
public String login() throws Exception {
remoteService.call();
return String.valueOf("11");
}
}
Spring Boot 整合 Spring Data
1)添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2)新建model和数据库表
package com.example.springdata.test;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* 描述:
* @author Ay
* @date 2017/08/22
*/
@Entity
public class AyTest {
@Id
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3)新建UserRepository
package com.example.springdata.test;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
/**
* @author Ay
* @date 2017/08/22
*/
public interface UserRepository extends CrudRepository<AyTest, String> {
List<AyTest> findByIdAndName(String id, String name);
}
4)测试类
package com.example.springdata.test;
import com.example.intellij.test.Ay;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.UUID;
/**
* Created by Ay on 2017/1/24.
*/
@RestController
@RequestMapping("/springdata")
public class SpringDataController {
@Autowired
private UserRepository userRepository;
@RequestMapping("/test")
public String index() {
AyTest ayTest = new AyTest();
ayTest.setId("60");
ayTest.setName("ay and al");
//select * from ay_test where id = '60' and name = "al"
List<AyTest> ayTestList = userRepository.findByIdAndName("60","ay and al");
return "Hello Ay...";
}
}
Spring Boot整合Websocket
【1】
第一步:引入pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
第二步:使用@ServerEndpoint创立websocket endpoint
首先要注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。要注意,如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
第三步:
@ServerEndpoint(value = "/websocket")
@Component
public class MyWebSocket {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 连接建立成功调用的方法*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
try {
sendMessage(CommonConstant.CURRENT_WANGING_NUMBER.toString());
} catch (IOException e) {
System.out.println("IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("来自客户端的消息:" + message);
//群发消息
for (MyWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发生错误时调用
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}
/**
* 群发自定义消息
* */
public static void sendInfo(String message) throws IOException {
for (MyWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
MyWebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
MyWebSocket.onlineCount--;
}
}
第四步:
<!DOCTYPE HTML>
<html>
<head>
<title>My WebSocket</title>
</head>
<body>
Welcome<br/>
<input id="text" type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button>
<div id="message">
</div>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
websocket = new WebSocket("ws://localhost:8084/websocket");
}
else{
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function(){
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websocket.onopen = function(event){
setMessageInnerHTML("open");
}
//接收到消息的回调方法
websocket.onmessage = function(event){
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function(){
setMessageInnerHTML("close");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
websocket.close();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭连接
function closeWebSocket(){
websocket.close();
}
//发送消息
function send(){
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
结束语
读书感悟
来着《战狼2》
- 犯我中华者,虽远必诛。
- 当兵后悔两年,不当兵后悔一辈子呀!
- 这种距离不是要打架就是要接吻。
- 美丽的地方,都有故事。
经典故事
有个老人在河边钓鱼,一个小孩走过去看他钓鱼,老人技巧纯熟,所以没多久就钓上了满篓的鱼,老人见小孩很可爱,要把整篓的鱼送给他,小孩摇摇头,老人惊异的问道:「你为何不要?」小孩回答:「我想要你手中的钓竿。」老人问:「你要钓竿做什么?」小孩说:「这篓鱼没多久就吃完了,要是我有钓竿,我就可以自己钓,一辈子也吃不完。」
我想你一定会说:好聪明的小孩。错了,他如果只要钓竿,那他一条鱼也吃不到。因为,他不懂钓鱼的技巧,光有鱼竿是没用的,因为钓鱼重要的不在“钓竿”,而在“钓技”。
[有太多人认为自己拥有了人生道上的钓竿,再也无惧于路上的风雨,如此,难免会跌倒于泥泞地上。就如小孩看老人,以为只要有钓竿就有吃不完的鱼,像职员看老板,以为只要坐在办公室,就有滚进的财源。]
大神文章
无