JoyLau's Blog

JoyLau 的技术学习与思考

前言

  • 使用很简单
  • 关注业务开发
  • 熟悉提供的注解

开始

引入依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>

配置启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@SpringBootApplication
@EnableSwagger2
public class JoylauSwagger2Application {

public static void main(String[] args) {
SpringApplication.run(JoylauSwagger2Application.class, args);
}

@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("cn.joylau.code"))
.paths(PathSelectors.any())
.build();
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring Boot构建RESTful APIs")
.description("将每一个注解的@RestController和@ResponseBody的类和方法生成API,点击即可展开")
.termsOfServiceUrl("http://blog.joylau.cn")
.contact(new Contact("joylau","http://blog.joylau.cn","2587038142@qq.com"))
.license("The Apache License, Version 2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.version("1.0")
.build();
}
}

注解说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@RestController
@RequestMapping(value="/users") // 通过这里配置使下面的映射都在/users下,可去除
public class UserController {

static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

@ApiOperation(value="获取用户列表", notes="")
@RequestMapping(value={""}, method= RequestMethod.GET)
public List<User> getUserList() {
List<User> r = new ArrayList<User>(users.values());
return r;
}

@ApiOperation(value="创建用户", notes="根据User对象创建用户")
@ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
@RequestMapping(value="", method=RequestMethod.POST)
public String postUser(@RequestBody User user) {
users.put(user.getId(), user);
return "success";
}

@ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息")
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
@RequestMapping(value="/{id}", method=RequestMethod.GET)
public User getUser(@PathVariable Long id) {
return users.get(id);
}

@ApiOperation(value="更新用户详细信息", notes="根据url的id来指定更新对象,并根据传过来的user信息来更新用户详细信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long"),
@ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
})
@RequestMapping(value="/{id}", method=RequestMethod.PUT)
public String putUser(@PathVariable Long id, @RequestBody User user) {
User u = users.get(id);
u.setName(user.getName());
u.setAge(user.getAge());
users.put(id, u);
return "success";
}

@ApiOperation(value="删除用户", notes="根据url的id来指定删除对象")
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
@RequestMapping(value="/{id}", method=RequestMethod.DELETE)
public String deleteUser(@PathVariable Long id) {
users.remove(id);
return "success";
}

}

常见注解

  • @Api:修饰整个类,描述Controller的作用
  • @ApiOperation:描述一个类的一个方法,或者说一个接口
  • @ApiParam:单个参数描述
  • @ApiModel:用对象来接收参数
  • @ApiProperty:用对象接收参数时,描述对象的一个字段
  • @ApiResponse:HTTP响应其中1个描述
  • @ApiResponses:HTTP响应整体描述
  • @ApiIgnore:使用该注解忽略这个API
  • @ApiClass
  • @ApiError
  • @ApiErrors
  • @ApiParamImplicit
  • @ApiParamsImplicit

最后

注意

  • Swagger2默认将所有的Controller中的RequestMapping方法都会暴露,然而在实际开发中,我们并不一定需要把所有API都提现在文档中查看,这种情况下,使用注解@ApiIgnore来解决,如果应用在Controller范围上,则当前Controller中的所有方法都会被忽略,如果应用在方法上,则对应用的方法忽略暴露API

或者重写方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Docket createRestApi() {
Predicate<RequestHandler> predicate = new Predicate<RequestHandler>() {
@Override
public boolean apply(RequestHandler input) {
Class<?> declaringClass = input.declaringClass();
if (declaringClass == BasicErrorController.class)// 排除
return false;
if(declaringClass.isAnnotationPresent(RestController.class)) // 被注解的类
return true;
if(input.isAnnotatedWith(ResponseBody.class)) // 被注解的方法
return true;
return false;
}
};

前言

本文说明

  • 使用之前rabbitMQ的介绍我就不说了,我认为你已经了解了
  • rabbitMQactiveMQ的对比区别我也不说了,我认为你已经查过资料了
  • rabbitMQ的安装,我也不说了,我认为你下载的时候已经看到了官网的安装说明,给一个Windows安装的链接:http://www.rabbitmq.com/install-windows.html
  • rabbitMQweb插件的启用,我也不说,我认为你已经会了
  • 那我们开始吧

入门使用

在使用之前先看一下rabbitMQ-client的使用

先引入依赖:

1
2
3
4
5
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.0</version>
</dependency>

在看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public void product() throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ地址
factory.setHost("localhost");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
//创建一个新的连接
Connection connection = factory.newConnection();
//创建一个频道
Channel channel = connection.createChannel();
//声明一个队列 -- 在RabbitMQ中,队列声明是幂等性的(一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同),也就是说,如果不存在,就创建,如果存在,不会对已经存在的队列产生任何影响。
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
//发送消息到队列中
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
System.out.println("P [x] Sent '" + message + "'");
//关闭频道和连接
channel.close();
connection.close();
}


public void consumer() throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ地址
factory.setHost("localhost");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
//创建一个新的连接
Connection connection = factory.newConnection();
//创建一个频道
Channel channel = connection.createChannel();
//声明要关注的队列 -- 在RabbitMQ中,队列声明是幂等性的(一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同),也就是说,如果不存在,就创建,如果存在,不会对已经存在的队列产生任何影响。
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println("C [*] Waiting for messages. To exit press CTRL+C");
//DefaultConsumer类实现了Consumer接口,通过传入一个频道,告诉服务器我们需要那个频道的消息,如果频道中有消息,就会执行回调函数handleDelivery
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println("C [x] Received '" + message + "'");
}
};
//自动回复队列应答 -- RabbitMQ中的消息确认机制
channel.basicConsume(QUEUE_NAME, true, consumer);
}

代码的注释很详细

SpringBoot中的使用

引入依赖

1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>

配置文件

1
2
3
4
5
6
7
8
9
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
output:
ansi:
enabled: always

生产者

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class Product {
@Autowired
private AmqpTemplate rabbitTemplate;

public void send() {
String context = "hello " + new Date();
System.out.println("生产者发送信息 : " + context);

new Queue("hello");
this.rabbitTemplate.convertAndSend("hello", context);
}
}

创建消息生产者Product。通过注入AmqpTemplate接口的实例来实现消息的发送,AmqpTemplate接口定义了一套针对AMQP协议的基础操作。在Spring Boot中会根据配置来注入其具体实现。在该生产者,我们会产生一个字符串,并发送到名为hello的队列中

消费者

1
2
3
4
5
6
7
8
@Component
@RabbitListener(queues = "hello")
public class Consumer {
@RabbitHandler
public void process(String hello) {
System.out.println("消费者接受信息 : " + hello);
}
}

创建消息消费者Consumer。通过@RabbitListener注解定义该类对hello队列的监听,并用@RabbitHandler注解来指定对消息的处理方法。所以,该消费者实现了对hello队列的消费,消费操作为输出消息的字符串内容。

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringRunner.class)
@SpringBootTest
public class JoylauSpringBootRabbitmqApplicationTests {

@Autowired
private Product product;

@Test
public void test() throws Exception {
product.send();
}

}

再来一张图

示例截图

exchange 多个消费者

当Exchange和RoutingKey相同、queue不同时,所有消费者都能消费同样的信息
Exchange和RoutingKey、queue都相同时,消费者中只有一个能消费信息,其他消费者都不能消费该信息。

下面示例的队列名称可以随意写个,启动时 @RabbitListener 的 bindings 会自动使用 key 绑定队列到exchange

1
2
3
4
5
6
7
8
9
10
@RabbitHandler
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = "${spring.application.name}"),
exchange = @Exchange(value = "${spring.rabbitmq.template.exchange}"),
key = "${spring.rabbitmq.template.routing-key}")
)
public void listenerTrafficMessage(Message message){
System.out.println(message.getClass().getName());
}

消息返回队列

需要处理完消息后在将消息返回队列的话需要配置 spring.rabbitmq.listener.simple.acknowledge-mode: manual
之后注解@RabbitListener 到方法上
Channel channel 进行返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RabbitHandler
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = "${spring.application.name}"),
exchange = @Exchange(value = "${spring.rabbitmq.template.exchange}"),
key = "${spring.rabbitmq.template.routing-key}")
)
public void listenerTrafficMessage(Message message, Channel channel){

System.out.println(message.getClass().getName());

try {
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
} catch (IOException e) {
e.printStackTrace();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring:
rabbitmq:
host: 192.168.10.224
port: 35672
username: guest
password: guest
virtual-host: /
listener:
simple:
acknowledge-mode: manual #设置消费端手动 ack
concurrency: 1 #消费者最小数量
max-concurrency: 1 #消费者最大数量
prefetch: 1 #在单个请求中处理的消息个数,他应该大于等于事务数量(unack的最大数量)
template:
exchange: SURVEY_CENTER
routing-key: trafficCongestionSituationBD

在属性配置文件里面开启了ACK确认 所以如果代码没有执行ACK确认 你在RabbitMQ的后台会看到消息会一直留在队列里面未消费掉 只要程序一启动开始接受该队列消息的时候 又会收到

1
2
3
// 告诉服务器收到这条消息 已经被我消费了 可以在队列删掉 这样以后就不会再发了
// 否则消息服务器以为这条消息没处理掉 后续还会在发,true确认所有消费者获得的消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);

丢弃消息

1
2
3
4
5
6
7
8
9
10
//最后一个参数是:是否重回队列
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
//拒绝消息
//channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
//消息被丢失
//channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
//消息被重新发送
//channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
//多条消息被重新发送
//channel.basicNack(message.getMessageProperties().getDeliveryTag(), true, true);

Windows下最适合编程的字体要数Consolas字体了,那么如何将命令提示符换成Consolas字体呢?我们只需要注册以下信息即可:

1
2
3
4
5
6
7
8
9
10
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe]
"WindowSize"=dword:00170058
"ScreenBufferSize"=dword:01170058
"WindowPosition"=dword:0079004b
"ColorTable01"=dword:00235600
"FontSize"=dword:00120000
"FontWeight"=dword:00000190
"FaceName"="Consolas"
"FontFamily"=dword:00000036

新建一个文本文件,将信息保存到此文本文件中
然后将文本文件重命名为*.reg
双击此文件将其注册

通常的属性注入

一般情况下我们使用Spring或者SpringMVC的时候会使用@Value()注入

使用SpringBoot的时候会使用@ConfigurationProperties(prefix = "xxxx")

注入自定义的呢?这样:@ConfigurationProperties(prefix = "xxx",locations = "classpath:config/xxxx.properties")

更复杂一点的注入

如上图所示我注入了一个List<String>

拓展

那么同样的方式,是否可以注入Map,String[]….呢?

思考

properties的文件被读取的时候使用的就是Map,那么我们知道Map是无序了,这样就会导致我们原先要求的一致性可能达不到

解决方式

properties文件改成采用yml文件,或者升级SpringBoot的版本,貌似新版本采用的LinkedHashMap

引用本地包并打包部署的问题

背景

  • 在最近的开发中需要对接C++服务提供的ZeroC Ice接口,客户机环境安装了和服务环境相同的Ice,服务端的Ice比较老,是3.4.0的版本
    在maven的中央仓库中没有找到ice-3.4.0的jar包,只能引用安装路径下提供的jar了

那么常用的写法是这样的:(包括但不限于SpringBoot)

1
2
3
4
5
6
7
8
<!--Ice-->
<dependency>
<groupId>Ice</groupId>
<artifactId>Ice</artifactId>
<version>3.4.0</version>
<scope>system</scope>
<systemPath>${basedir}/src/lib/Ice.jar</systemPath>
</dependency>

我是在src下新建的lib目录,在开发编译的是没有问题的。

在进行打包的时候发现Ice.jar没有被打进去

相对于这个应用来说,打成jar包是最合适的做法了

这里说一下,用package打包,不要用SpringBoot插件的jar打包

解决

build里加上这一段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
..............
<resources>
<resource>
<directory>src/lib</directory>
<targetPath>BOOT-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<targetPath>BOOT-INF/classes/</targetPath>
</resource>
</resources>
</build>

之后,再打包,再解压一看,果然是打进去了,完美~

然后,遇到了新问题……..

以jar运行时没有主清单属性

之后便很愉快的使用 java -jar xxxxx.jar

提示:没有主清单属性

再解压一看,有Application.java类,但是jar包的大小明显不对,光SpringBoot父项目依赖的jar至少也有10+M了,这个大小明显不对

在结合没有主属性的错误,知道了错误的原因在这:

1
2
3
4
5
6
7
8
9
10
11
   <dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependencyManagement>

我用的项目是多模块依赖

解决的方式是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot-dependencies.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</build>

正如我文章截图的那样,解决问题!

父项目依赖,打包成jar

同时加入以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

2017年9月19日更新

SpringBoot 项目打包时修改 MANIFEST.MF 文件

一般情况下我们的 MANIFEST.MF内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Manifest-Version: 1.0
Implementation-Title: joylau-media
Implementation-Version: 1.7-RELEASE
Archiver-Version: Plexus Archiver
Built-By: JoyLau
Implementation-Vendor-Id: cn.joylau.code
Spring-Boot-Version: 1.5.4.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: cn.joylau.code.JoylauMediaApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.5.0
Build-Jdk: 1.8.0_45
Implementation-URL: http://projects.spring.io/spring-boot/joylau-media
/

解决:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!--fork : 如果没有该项配置,肯呢个devtools不会起作用,即应用不会restart -->
<fork>true</fork>
</configuration>
</plugin>

//修改版本号,一般为pom文件的版本
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifestEntries>
<Manifest-Version>${version}</Manifest-Version>
</manifestEntries>
</archive>
</configuration>
</plugin>

SpringBoot 项目中引入缓存

  • 引入依赖
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

@EnableCaching 开启缓存

@CacheConfig(cacheNames = “api_cache”) 配置一个缓存类的公共信息

@Cacheable() 注解到方法上开启缓存

@CachePut() 根据使用的条件来执行具体的方法

@CacheEvict() 根据配置的参数删除缓存

SpringBoot默认支持很多缓存,spring.cache.type就可以知道,默认的是实现的是SimpleCacheManage,这里我记一下怎么设置缓存的超时时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
@EnableCaching
@EnableScheduling
public class CachingConfig {
public static final String CACHENAME = "api_cache";
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager(CACHENAME);
}
@CacheEvict(allEntries = true, value = {CACHENAME})
@Scheduled(fixedDelay = 120 * 1000 , initialDelay = 500)
public void reportCacheEvict() {
System.out.println("Flush Cache " + dateFormat.format(new Date()));
}
}

这里巧妙的使用了 定时任务,再其加上注解CacheEvict来清除所有cache name 为 api——cache 的缓存,超时时间是120s

在说说我比较喜欢的使用方式

单独写了篇文章,戳下面:

持续更新中…

问题

  • 用jackson 作为json转换器的时候,如果传入的json的key 比接收对象多的话,就会报错

解决

先看下SpringMVC原来的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>

这里的json转换器配置的是:org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

我们进入到这个类中发现,这个类是继承的 AbstractJackson2HttpMessageConverter

AbstractJackson2HttpMessageConverter 继承的是 AbstractHttpMessageConverter<Object>
找到这个包下面 有一个类 GsonHttpMessageConverter 同样继承的 AbstractHttpMessageConverter<Object>
OK,就是他了

1
2
3
4
5
6
7
8
9
10
11
12
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>

这样,参数就随便你整吧,多点少点杜无所谓,完全匹配不上就返回个{}给你

来看下fastjson

fastjson下面有这个一个 package : com.alibaba.fastjson.support.spring

根据字面意思可知,这里是对spring的支持

找到下面这个class FastJsonHttpMessageConverter

1
public class FastJsonHttpMessageConverter extends AbstractHttpMessageConverter<Object>

OK,这个类同样也是继承了 AbstractHttpMessageConverter

只要把这个类注入进去就可以了

SpringBoot使用FastJSON解析数据

  • 第一种继承WebMvcConfigurerAdapter,重写configureMessageConverters方法:
1
2
3
4
5
6
7
8
9
10
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
FastJsonHttpMessageConverter converter=new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig= new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
converter.setFastJsonConfig(fastJsonConfig);
converters.add(converter);

}
  • 第二种方式bean注入HttpMessageConverters:
1
2
3
4
5
6
7
8
9
@Bean  
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}

2017年普通高等学校招生全国统一考试

程序员的高考试卷(A卷) `考生类别:码农`

1、程序员A:借我1000元吧。程序员B:给你凑个整数。程序员B借给程序员A多少钱?()

   A. 1000元
   B. 1024元
   C. 1111元

2、程序员A:嘿 //是什么意思啊?程序员B:嘿.程序员A:呃 我问你//是什么意思?程序员B:问吧.程序员A:我刚才不是问了么?程序员B:啊?程序员A到底问了程序员B什么问题?()

   A. 嘿
   B. 呃 我问你
   C. //是什么意思

3、为什么程序员分不清万圣节和圣诞节?()

   A. 因为 31 OCT == 25 DEC
   B. 程序员只有加班/不加班,不过节
   C. 程序员没有女朋友,不过节

4、程序员最怕弹出的窗口是()

   A.   选项A

   B.   选项B

   C.   选项C

5、程序员:哎,太累了日子没法过了,怎么才能换行啊?()

   A. 打回车
   B. 不换行,日子不过了
   C. 除了敲代码,都不会,换行还是敲代码啊

6、程序员会给自己的孩子起什么名字?()

   A. 依依、灵灵、依灵、灵依、依初
   B. Ctrl、Alt 、Delete
   C. 程序员怎么会有女朋友?

7、如何快速挣到一百万?()

   A. while
   B. 买彩票
   C. 当乞丐

8、程序员下班前给老婆打电话:老婆,晚饭我带回来吃,你说买些啥?老婆:买1斤包子吧,如果遇到卖西瓜的,就买一个。程序员买包子时,看到旁边有人在卖西瓜。那么,程序员带了什么晚饭回家?()

   A. 1斤包子
   B. 1个包子
   C. 1个西瓜

9、我GET不到你的笑点,怎么办?()

   A. 智商不在一条线
   B. 太矮了,踩凳子上
   C. 用Post试试

10、为什么吸烟的程序员不在乎香烟盒上的那个警告?()

   A. 字太小
   B. 程序员眼中只有程序
   C. 不关心Warning,只关心Error

11、一对程序员恋人面对面坐着,他们在做什么?()

   A. 面向对象编程
   B. 喝咖啡
   C. 抱怨产品经理

12、老板:小程,下班前新版本一定要上线!小程:好的。第二天,老板上班,问小程:新版本怎么还没上线? 小程怎么回答的?()

   A. 版本出问题了
   B. 版本上线前需求又改了
   C. 我还没下班呢

![Title](//s3.joylau.cn:9000/blog/gaokao-title.jpg)

2017年普通高等学校招生全国统一考试

程序员的高考试卷(B卷) `考生类别:码神`

1、以下哪个概念和公孙龙的《指物论》中的“指”字含义相近?()

   A. 变量
   B. 数组
   C. 对象
   D. 指针

2、蔺相如,司马相如;魏无忌,长孙无忌。下列哪一组对应关系与此类似( )

   A. PHP,Python
   B. JSP,servlet
   C. java,java script
   D. C,C++

3、秦始皇吞并六国采用了以下哪种算法思想?( )

   A. 递归
   B. 分治
   C. 迭代
   D. 模拟

4、雅典王子忒修斯勇闯克里特岛斩杀米诺牛的时候采用了以下哪种算法?( )

   A. 动态规划
   B. 穷举
   C. 记忆化搜索
   D. Dijkstra算法

5、众里寻他千百度,蓦然回首,那人却在灯火阑珊处(辛弃疾《青玉案》)。所体现的算法是:( )

   A. 贪心
   B. 回溯
   C. 穷举
   D. 分治

6、《公孙龙子》记载:“齐王之谓尹文曰:‘寡人甚好士,以齐国无士,何也?’尹文曰:‘愿闻大王之所谓士者。’齐王无以应。”这说明了齐王:( )

   A. 昏庸无道
   B. 是个结巴
   C. 不会下定义
   D. 不会定义自己的需求

7、惠施曾提出过“卵有毛”的命题,以下哪一项是导致这个错误命题的原因:( )

   A. 混淆了命名空间
   B. 引入了错误的包
   C. 衍生类未重载
   D. 调用了危险的指针

8、下面哪种面向对象的方法可以让你变得富有?( )

   A. 继承
   B. 封装
   C. 多态
   D. 抽象

那么你能答对几题呢? 下期发布标准答案 滑稽

先来一张集合的

java-skill-tree1

Java核心技术总结

java-skill-tree2

J2EE技术总结

java-skill-tree3

工作学习总结

java-skill-tree4

大数据相关技术总结

java-skill-tree5

来看看Java工程师技能表

java-skill-tree6
java-skill-tree8
java-skill-tree9

恐怖的Linux大法

java-skill-tree7

0%