anxpp的博客 http://blog.anxpp.com/ zh-CN As they sow , so let them reap . Sat, 01 Jul 2017 04:39:00 +0000 Sat, 01 Jul 2017 04:39:00 +0000 此内容被密码保护 http://blog.anxpp.com/index.php/archives/513/ http://blog.anxpp.com/index.php/archives/513/ Fri, 26 Feb 2016 10:29:00 +0000 anxpp

请输入密码访问

]]>
0 http://blog.anxpp.com/index.php/archives/513/#comments http://blog.anxpp.com/index.php/feed/archives/513/
虚拟机最小化安装 Centos7 的网络配置 http://blog.anxpp.com/index.php/archives/1080/ http://blog.anxpp.com/index.php/archives/1080/ Sat, 01 Jul 2017 04:39:00 +0000 anxpp

我不是针对谁,我是说国内大多数技术社区,都是辣鸡。

原文出自:http://blog.anxpp.com/index.php/archives/1080/

    (强迫症患者都想要个干干净净的系统)使用虚拟机最小化安装了 Centos 7 ,安装完成肯定是上不了网的,搜了下,结果都是千篇一律(估计国内的技术文章原创与抄来的比例差不多1:99吧,这不是重点,重点是抄过来都不带验证的!)

 

    直接上配置方法(笨有笨的方法,本人是通过安装 桌面版 Centos 验证并解决问题的...):

    虚拟机配置:

* 建议配置前重置下虚拟网络配置:
    菜单栏 --> 编辑 --> 虚拟网络编辑器 --> (左下角)还原默认设置
1、右键当前虚拟机选项卡
2、硬件 --> 网络适配器 --> 选择第一个桥接模式,附加选项(复制物理网络连接状态)不用选择。解释:现在联网基本都是过路由的,也就是连上网线可以直接上网的,固可选改方式连接上网。

 

    命令:

ip addr

    结果应该是没有显示有地址相关的信息的,表示网络根本没有启动。

 

    开启网络连接:

ifup ens33

    这里的 ens33 是网卡的名称,不同安装可能会有差异,在上面的 ip addr 命令的结果中会有显示实际名称。

    或者到目录 /etc/sysconfig/network-scripts/ 下能看到相关的配置文件,比如我的配置文件是 ifcfg-ens33 。

 

    重启网络服务:

systemctl restart network

    这时应该是可以上网了,可以 ping 一下或者 ip addr 看下网络地址情况。

 

    最小化安装很多命令都是不能运行的,不过可以自己安装响应的工具包添加支持。

 

    如果希望一直保存系统的干净,那就装个 Docker 吧(很多时候虽然这是多余的,使用虚拟机本来保证了宿主机是干净的...),所有东西都塞里面。

 

    如果以上步骤依然不能解决,可以考虑如下情况搜索相关资料:

    1、虚拟机安装 centos mac 地址问题

    2、关闭 NetworkManager

 

    欢迎交流学习!

]]>
0 http://blog.anxpp.com/index.php/archives/1080/#comments http://blog.anxpp.com/index.php/feed/archives/1080/
使用Jenkins发布spring boot应用到docker http://blog.anxpp.com/index.php/archives/1079/ http://blog.anxpp.com/index.php/archives/1079/ Mon, 26 Jun 2017 09:17:00 +0000 anxpp 0 http://blog.anxpp.com/index.php/archives/1079/#comments http://blog.anxpp.com/index.php/feed/archives/1079/ spring boot 应用发布到 docker 完整版 http://blog.anxpp.com/index.php/archives/1075/ http://blog.anxpp.com/index.php/archives/1075/ Mon, 19 Jun 2017 17:15:00 +0000 anxpp

原文出自:http://blog.csdn.net/anxpp/article/details/73478883

Spring boot 非常适合做微服务,如果再加上 docker ,就就就完美了!

By  鱼泡泡技术团队

spring boot 应用发布到 docker 完整版

一、概述

    spring boot 和 docker 本身就不多介绍了,本文主要介绍使用 docker-maven-plugin 插件,直接将 spring boot 应用一键发布到 docker 容器中。

    文末会提供源码 Git 地址。

    笔者 docker 部署于一台 Centos 7.2 的云服务器,换做 VM 虚拟机的 Linux 也是一样的。

    用到的所涉及的软件版本皆为当前最新的,构建工具为 maven,如果使用的其他工具,请使用对应步骤替换。

 

二、安装并配置 Docker

    笔者用于测试的 Linux 为 Centos,其他系统也差不太多。

    1、安装 Docker

    直接使用 yum 安装即可:

sudo yum install docker

    安装完成后可以通过如下命令查看是否安装成功:

docker version

    如果正常输出版本等相关信息,即表示安装成功。

    2、配置 Docker Remote API

    docker-maven-plugin 插件是使用的 Docker Remote API 进行远程提交镜像的,docker 默认并没有开启该选项,直接修改 docker 服务配置即可,

Centos 下配置文件位于:/usr/lib/systemd/system/docker.service

    直接在 ExecStart 启动参数的 /usr/bin/dockerd 后面添加以开启 TCP 连接:-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock

    也可在此增加 Docker Hub 镜像加速地址,修改完成后完整的配置如下:

[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target
Wants=docker-storage-setup.service
Requires=docker-cleanup.timer
[Service]
Type=notify
NotifyAccess=all
KillMode=process
EnvironmentFile=-/etc/sysconfig/docker
EnvironmentFile=-/etc/sysconfig/docker-storage
EnvironmentFile=-/etc/sysconfig/docker-network
Environment=GOTRACEBACK=crash
Environment=DOCKER_HTTP_HOST_COMPAT=1
Environment=PATH=/usr/libexec/docker:/usr/bin:/usr/sbin
ExecStart=/usr/bin/dockerd --registry-mirror=https://registry.docker-cn.com -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock \
          --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current \
          --default-runtime=docker-runc \
          --exec-opt native.cgroupdriver=systemd \
          --userland-proxy-path=/usr/libexec/docker/docker-proxy-current \
          $OPTIONS \
          $DOCKER_STORAGE_OPTIONS \
          $DOCKER_NETWORK_OPTIONS \
          $ADD_REGISTRY \
          $BLOCK_REGISTRY \
          $INSECURE_REGISTRY
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
TimeoutStartSec=0
Restart=on-abnormal
MountFlags=slave
[Install]
WantedBy=multi-user.target

    重新载入 systemd,扫描新的或有变动的单元(docker):

systemctl daemon-reload docker

    启动 docker(如果已启动,则使用restart):

systemctl start docker

    本地测试:

 curl http://localhost:2375

    如果没报错基本就是完成了。我的工作环境是windows的,没安装 curl 工具,直接在浏览器输入 http://ip:2375 也是可以远程测试的,如果无法访问,请检查 docker 所在服务器的防火墙配置等。

    3、下载父镜像

    这一步不是必须的,Docker 会根据 Dockerfile 生成镜像时自动下载需要的依赖,但是为了后面完成 Spring boot 应用后构建并发布到 Docker 时不至于傻傻的等,这里可以先将父镜像 pull 到本地。

    java8 运行环境的 docker 镜像目前最受欢迎的是 frolvlad/alpine-oraclejdk8 ,那我们就用他吧:

docker pull frolvlad/alpine-oraclejdk8

    这可能会耗时一会儿,不过可以放这儿不用管,直接进行下一步。

    通常不指定镜像版本,默认会 pull 当期镜像的 latest 版本。

 

三、完成一个 Spring boot 应用并添加 docker-maven-plugin 插件

    1、完成 Spring boot 应用

    Eclipse 可以安装 STS 插件,Idea 也自带 Spring Boot 工程一键生成工具,这里直接生成一个最简单的 Web 工程,并在启动代码中加入少许代码以对外提供一个简单的接口用于测试:

package com.anxpp.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DockerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DockerApplication.class, args);
    }
    @RequestMapping
    public String index(){
        return "Hello world !";
    }
}

    完成后可以运行并访问 http://localhost:8080 测试是否正常工作。

    2、添加 docker-maven-plugin 插件

    插件最新版本为 0.4.13,此处还是贴完整的 pom 文件吧:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.anxpp.demo</groupId>
    <artifactId>docker</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>docker</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <docker.image.prefix>anxpp</docker.image.prefix>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.4.13</version>
                <configuration>
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <dockerHost>http://***.***.anxpp.com:2375</dockerHost>
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

    imageName 指定生成的镜像名称,dockerHost 指定 Docker Remote API 的远程访问地址,这里请自行按照实际情况填写。

    3、编写 Dockerfile

    我们需要在 src/main/docker 下添加 Dockerfile 文件(当然,这在上一步添加插件的时候也是可以配置的),Dockerfile 如何写请参考 docker 相关文章,文末也会给连接。完整的文件内容如下:

FROM frolvlad/alpine-oraclejdk8
VOLUME /tmp
ADD docker-0.0.1-SNAPSHOT.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

    ADD 后面请按照实际情况填写自己 package 生成的 jar 文件名称。

 

四、构建

    1、生成镜像

    首先需要运行 maven 的 package 命令生成 jar 文件,直接运行 docker:build 会因为找不到 jar 文件而构建失败!

mvn clean package

    现在的 IDE 也都会提供图形化工具,拖着鼠标点点点就行了。

    现在回头看看 二、3 中的父镜像有没有下载好,如果已经下载好即可进行下面的步骤(可以输入命令查看镜像列表)。

    打包完成后运行 docker:build 。

    如果一切顺利,那么镜像就生成好了并推送到 docker 中,输入如下命令查看镜像列表:

docker images

    如果列表中有我们刚刚生成的镜像,那么表示以上步骤都是成功的(废话)。

    2、运行

    镜像运行后就成为容器,使用如下命令运行启动刚刚生成的镜像:

docker run -d -p 8080:8080 -t anxpp/docker

    -d 是让容器后台运行

    -p 是将容器内的端口映射到 docker 所在系统的端口

    -t 是打开一个伪终端,以便后续可以进入查看控制台 log

    查看运行中的容器:

docker ps

    可以使用浏览器访问测试是否一切都很顺利:

    http://***.***.anxpp.com:8080

    那么,用 docker 构建、运行和发布一个 Spring Boot 应用到此源码结束,深藏功与名。

 

五、多说几句

    Docker 文章参考:Docker基础教程及实践专栏

    Spring boot 应用源码 GitHub:https://github.com/anxpp/springboot-docker-demo.git

    有问题赶紧留言吧,趁我还记得...

]]>
1 http://blog.anxpp.com/index.php/archives/1075/#comments http://blog.anxpp.com/index.php/feed/archives/1075/
Spring REST Docs 简易教程 http://blog.anxpp.com/index.php/archives/1071/ http://blog.anxpp.com/index.php/archives/1071/ Fri, 16 Jun 2017 17:09:00 +0000 anxpp

Spring REST Docs 简易教程



简介

Spring REST Docs 可以生成准确可读的RESTful Service文档(当然一般的API文档也就更加得心应手了)。

Spring 官方文档都是用 Spring REST Docs 生成的,其简洁性和可读性也是大家都认可的,不过 Spring REST Docs 的优势远不止于此:

  • 代码无污染:Spring REST Docs 基于单元测试生成文档片段(snippets),不会侵入到源码中,所以就不会使得源码变得越来越臃肿。
  • 单元测试:因为文档的生成是依赖单元测试的,以此可以矫正一些不爱写单元测试的程序员小哥哥。
  • 支持 markdown:修改一行配置代码即可支持生成 MarkDown 语法的文档片段(不过要生成html文档目前官方只支持adoc文档)。
  • 文档自动更新:文档自动更新?文档自动更新!默认的,在构建的时候,会首先运行单元测试,此时便生成了文档片段,然后在打包时,通过添加 asciidoctor-maven-plugin 插件即可生成最终的文档,只要是规范的开发过程,文档都会随版本的每次发布而自动更新!
  • 可读性高:Spring 官方文档就是个例子。
  • ……

Spring官方文档示例

我不是针对谁,我是说 Spring 全家桶的每一个组件,都堪称极品。


整合 Spring REST Docs

Spring REST Docs 同时支持Maven和Gradle,不过个人偏爱Maven,一下仅介绍Maven下的整合,Gradle请查看官方文档。 
生成文档片段的单元测试同时支持 Spring MVC Test 和 REST Assured 2/3,对比了一下,Spring MVC Test的代码更加简洁, 
所以本文也使用 Spring MVC Test 来做单元测试,如果有兴趣使用 Assured 的,依然还是参考官方文档吧。

Build configuration

在pom.xml文件中添加依赖和构建插件:

  • spring-restdocs-mockmvc用于编写单元测试
  • 添加Asciidoctor插件
  • prepare-package 参数允许文档被添加到程序包中
 
<dependency> 
    <groupId>org.springframework.restdocs</groupId>
    <artifactId>spring-restdocs-mockmvc</artifactId>
    <version>1.2.1.RELEASE</version>
    <scope>test</scope>
</dependency>
<build>
    <plugins>
        <plugin> 
            <groupId>org.asciidoctor</groupId>
            <artifactId>asciidoctor-maven-plugin</artifactId>
            <version>1.5.3</version>
            <executions>
                <execution>
                    <id>generate-docs</id>
                    <phase>prepare-package</phase> 
                    <goals>
                        <goal>process-asciidoc</goal>
                    </goals>
                    <configuration>
                        <backend>html</backend>
                        <doctype>book</doctype>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency> 
                    <groupId>org.springframework.restdocs</groupId>
                    <artifactId>spring-restdocs-asciidoctor</artifactId>
                    <version>1.2.1.RELEASE</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

这样,在单元测试时,就能在对应的输出目录里生成对应的文档片段(adoc文档片段或者MarkDown文档片段)。

将文档打包到jar中

如果希望生成的jar中直接包含文档,可以在 maven-resources 插件中配置将文档添加到 jar 的指定目录中,如下是放到 static/docs 中:

 
<plugin> 
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.7</version>
    <executions>
        <execution>
            <id>copy-resources</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration> 
                <outputDirectory>
                    ${project.build.outputDirectory}/static/docs
                </outputDirectory>
                <resources>
                    <resource>
                        <directory>
                            ${project.build.directory}/generated-docs
                        </directory>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

打包时自动生成文档片段

文档片段是运行单元测试时自动生成的,Maven直接打包时一般是不会运行单元测试的(Gradle 在构建时默认是会运行单元测试的),不过做过全网回归的,基本都用过 maven 的 surefire 插件,生成文档的单元测试 .java 文件统一使用特定的后缀,然后每次打包前运行这些单元测试即可,配置如下:

 
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <includes>
            <include>**/*Documentation.java</include>
        </includes>
    </configuration>
</plugin>

生成文档片段

Spring REST Docs 通过 Spring’s MVC Test 向 service 发起请求来生成请求和响应相关信息的文档片段。

配置单元测试

首先需要声明一个 public 的 JUnitRestDocumentation ,并且加上 @Rule 注解,JUnitRestDocumentation 会按约定自动完成配置(约定大于配置),在 Maven 下默认文档片段输出目录为:target/generated-snippets

@Rule public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();

其中 JUnitRestDocumentation 提供一个带 String 参数的构造函数,用于指定自定义文档片段输出目录。

配置 MockMvc

 
private MockMvc mockMvc;
@Autowired
private WebApplicationContext context;
@Before
public void setUp() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
            .apply(documentationConfiguration(this.restDocumentation)) 
            .build();
}

此处使用了默认配置,不过 documentationConfiguration 也提供了api用于自定义配置,这在后面的配置一节中会介绍。

测试RESTful service

以上完成配置后,就可以开始使用 MockMvc 请求 RESTful service 并记录请求和响应的相关信息了:

this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andDo(document("index")); 
第一行请求根路径,并接受一个 application/json 的响应消息。 第二三行先是断言会得到一个预期的响应,并在配置的代码片段输出目录中新建一个 index 的目录,并在其中生成默认的文档片段。 

使用文档片段

我们需要编写 .adoc 后缀的将文档片段整合起来,目录为: 
src/main/asciidoc/.adoc,之后在打包是会自动生成最终的 html 文档,目录为:target/generated-docs/.html

可以根据文末提供的 Demo 编写 adoc 文档,最好是直接参考 asciidoctor 官方文档


为 API 编写文档

本节介绍如何使用 Spring REST Docs 为API 编写文档。

链接

为当前路径添加子路径的相关信息,感觉是专门为 RESTFul Service 提供的 API,使用方式为:

 
this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
    .andExpect(status().isOk())
    .andDo(document("index", links( 
            linkWithRel("alpha").description("Link to the alpha resource"), 
            linkWithRel("bravo").description("Link to the bravo resource")))); 

此处必须将每一个子路径都添加进来,否则单元测试会失败,这样其实也是为了更加规范,如果有的 link 不想添加进来,使用使用 ignored() 方法将其忽略掉,在文档片段中不会生成被忽略的 link 的相关信息。

如果实在不想把所有的可能的 link 都添加进来,可以使用 relaxedLinks 代替 links 从而不会导致单元测试失败。

类似 links 和 relaxedLinks,后面介绍的每一种文档记录方式都支持这两种方法(即严格模式和 relaxed 模式),此处一次说明,后续小节不再赘述。

格式化链接

默认的超链接格式有两种:

  • Atom – links are expected to be in an array named links. Used by default when the content type of the response is compatible with application/json.
  • HAL – links are expected to be in a map named _links. Used by default when the content type of the response is compatible with application/hal+json.

使用方式如下:

.andDo(document("index", links(halLinks(), linkWithRel("alpha").description("Link to the alpha resource"), linkWithRel("bravo").description("Link to the bravo resource"))));

如果 API 返回的链接格式是其他格式的,可以自己实现 LinkExtractor 以支持对应的格式。

忽略相同的链接

public static LinksSnippet links(LinkDescriptor... descriptors) { return HypermediaDocumentation.links(linkWithRel("_self").ignored().optional(), linkWithRel("curies").ignored()).and(descriptors); }

Request and response payloads

此处指的是消息体内的数据,虽然平常不管用 GET 还是 POST ,也不管参数是在 URL 后面拼接后传送的还是编码到消息主体内发送的,我们都统称为“参数”, 
不过在记录 API 的时候,还是得加以区分,而且对于 RESTFul 来说,这是很重要的。

根据Spring REST Doc官方文档,把 URL 后面拼接的参数叫做 parameter ,而编码到消息主体里的参数叫做 fields ,下面就分开介绍如何记录到文档中。

在请求完成后,默认会自动生成两个文档:request-body.adoc 和 response-body.adoc ,用来记录请求和响应。

Request fields

对于 Request fields 主要针对的是非 GET 方式提交时的参数,生成文档的方式如下:

.andDo(document("restful-user-add", requestFields( fieldWithPath("name").description("用户姓名"), fieldWithPath("sex").description("用户性别,0=女,1=男")) ));

此处同样支持使用 relaxedRequestFields 。

默认生成的文档片段文件名为:request-fields.adoc

Response fields

本文中所有数据默认都已Json的方式传输。 

对于响应消息中的信息,生成文档的方式与上面的类似:

.andDo(document("restful-user-list", responseFields( subsectionWithPath("_links").description("<<resources-restful-user-index,Links>> user resources"), subsectionWithPath("_embedded.user").description("用户列表").type("User对象数组"), subsectionWithPath("page").description("分页信息").type("Object"))));

同样提供 relaxedResponseFields 支持。

默认生成的文档片段文件名为:response-fields.adoc

Request parameters

请求参数通常包含在 GET 请求的 URL 中:

this.mockMvc.perform(post("/users").param("username", "Tester")) .andExpect(status().isCreated()) .andDo(document("create-user", requestParameters( parameterWithName("username").description("The user's username") )));

请求参数也可以作为表单数据包含在POST请求中:

this.mockMvc.perform(post("/users").param("username", "Tester")) .andExpect(status().isCreated()) .andDo(document("create-user", requestParameters( parameterWithName("username").description("The user's username") )));

relaxedRequestParameters 同样可用。

生成的文档片段文件名为:request-parameters.adoc

Path parameters

RESTFul 中大多数 API 都是将参数放到路径中的,这在一般的 API 中也常常这么多:

this.mockMvc.perform(get("/locations/{latitude}/{longitude}", 51.5072, 0.1275)) .andExpect(status().isOk()) .andDo(document("locations", pathParameters( parameterWithName("latitude").description("The location's latitude"), parameterWithName("longitude").description("The location's longitude") )));

提供 relaxedPathParameters

生成的文档片段为:path-parameters.adoc

HTTP 头

HTTP 请求头和相应头记录方式如下:

this.mockMvc .perform(get("/people").header("Authorization", "Basic dXNlcjpzZWNyZXQ=")) .andExpect(status().isOk()) .andDo(document("headers", requestHeaders( headerWithName("Authorization").description( "Basic auth credentials")), responseHeaders( headerWithName("X-RateLimit-Limit").description( "The total number of requests permitted per period"), headerWithName("X-RateLimit-Remaining").description( "Remaining requests permitted in current period"), headerWithName("X-RateLimit-Reset").description( "Time at which the rate limit period will reset"))));

生成的文档片段分别为:request-headers.adoc 和 response-headers.adoc

文档片段复用

很多参数、链接描述等其实是一样的,如果在每个接口里都写一遍难免比较麻烦,不过还是有办法可以复用这些代码的。比如分页中的链接可以预先定义好:

protected final LinksSnippet pagingLinks = links( linkWithRel("first").optional().description("The first page of results"), linkWithRel("last").optional().description("The last page of results"), linkWithRel("next").optional().description("The next page of results"), linkWithRel("prev").optional().description("The previous page of results"));

然后使用:

this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andDo(document("example", this.pagingLinks.and( linkWithRel("alpha").description("Link to the alpha resource"), linkWithRel("bravo").description("Link to the bravo resource"))));

配置

API 地址相关信息

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) .apply(documentationConfiguration(this.restDocumentation).uris() .withScheme("https") .withHost("example.com") .withPort(443)) .build();

这样,文档中出现的 HTTP 请求等的 Host 等信息就会以上面的配置为准了。

文档片段编码配置

默认为UTF-8,所以一般不需要配置,不过有特殊要求的话,可以如下配置:

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) .apply(documentationConfiguration(this.restDocumentation) .snippets().withEncoding("ISO-8859-1")) .build();

文档片段模板

文档片段支持生成两个格式,默认为 Asciidoctor ,也可以配置生成 MarkDown 格式的文档:

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) .apply(documentationConfiguration(this.restDocumentation) .snippets().withTemplateFormat(TemplateFormats.markdown())) .build();

默认的文档片段

默认生成的文档片段有 6 个:

  • curl-request
  • http-request
  • http-response
  • httpie-request
  • request-body
  • response-body

如果需要修改可以如下配置:

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) .apply(documentationConfiguration(this.restDocumentation).snippets() .withDefaults(curlRequest())) .build();

Asciidoctor

Asciidoctor 其实跟 MarkDown 挺像的,表达能力也比较强,但使用起来却很简单。

官方快速参考:http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/

官方完整文档:http://asciidoctor.org/docs/user-manual/

]]>
0 http://blog.anxpp.com/index.php/archives/1071/#comments http://blog.anxpp.com/index.php/feed/archives/1071/
MySQL使用一张表的字段更新另一张表的字段 http://blog.anxpp.com/index.php/archives/1069/ http://blog.anxpp.com/index.php/archives/1069/ Tue, 13 Jun 2017 04:44:00 +0000 anxpp     以下写法针对MySQL。

    写子查询也是可以实现的,不过当然应该选择一种更有效率的方式:

update table1 t1 left join table2 t2 on t1.key=t2.key set
    t1.field1=t2.field1,
    t1.field2=t2.field2,
    t1.field3=t2.field3
where t1.field4 is null and t2.field4 > '2017-04-27';

    该方式也比较灵活,ON条件和WHERE条件按需添加。

]]>
0 http://blog.anxpp.com/index.php/archives/1069/#comments http://blog.anxpp.com/index.php/feed/archives/1069/
MySQL表分区实践——(MySQL+emoji、制作ttf自定义Icon)编辑中...... http://blog.anxpp.com/index.php/archives/1067/ http://blog.anxpp.com/index.php/archives/1067/ Fri, 26 May 2017 05:08:00 +0000 anxpp     本文是最近MySQL分区实际操作的记录,Oracle分区介绍戳我

    最权威的文档当然是官方版了:Partitioning in MySQL

一、分区表简介

    本节主要引用官方文档介绍。

    检查所使用的MySQL是否支持分区,可以使用 SHOW PLUGINS 命令查看:

## 123

    1、

 

二、表分区实践

 

1、range分区

    MySQL版本:阿里云数据库MySQL(RDS)  5.6.34

 

2、

 

 

 

 

 

 

 

]]>
0 http://blog.anxpp.com/index.php/archives/1067/#comments http://blog.anxpp.com/index.php/feed/archives/1067/
基于Spring Boot+jsoup+redis抓取CSDN每周干货的RESTFul爬虫 http://blog.anxpp.com/index.php/archives/1057/ http://blog.anxpp.com/index.php/archives/1057/ Mon, 13 Mar 2017 15:05:00 +0000 anxpp     一个简单的爬虫,用于抓取csdn上的每周干货推荐。

    使用到的相关技术:SpringBoot、Redis、Jsoup、JQuery、Bootstrap等。

示例地址:

    http://tinyspider.anxpp.com/

效果图:

 

1、写在前面

    准备熟悉下Spring Boot + Redis的使用,所以就想到爬点东西出来,于是用上了号称Java版JQuery的Jsoup,实现的功能是获取每周的CSDN推荐文章,并缓存到Redis中(当然也可以持久化到数据库,相关配置已添加,只是没有实现),网页解析部分已抽象为接口,根据要抓取的不同网页,可以自定义对应的实现,也就是可以爬取任何网页了。

    解析网页的方法返回的数据为List<Map>,再定义对应的实体,可以直接反射为实体(已实现),具体见后文的代码介绍。

    下面介绍具体实现的步骤。

2、搭建Spring Boot并集成Redis

    Spring Boot工程的搭建不用多说了,不管是Eclipse还是Idea,Spring都提供了懒人工具,可根据要使用的组件一键生成项目。

    下面是Redis,首先是引入依赖:

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

    然后添加配置文件:

#Redis
spring.redis.database=0
spring.redis.host=****
spring.redis.password=a****
spring.redis.pool.max-active=8
spring.redis.pool.max-idle=8
spring.redis.pool.max-wait=-1
spring.redis.pool.min-idle=0
spring.redis.port=****
#spring.redis.sentinel.master= # Name of Redis server.
#spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs.
spring.redis.timeout=0

    ip和端口请自行根据实际情况填写。

    然后是配置Redis,此处使用JavaConfig的方式:

package com.anxpp.tinysoft.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
/**
 * Redis缓存配置
 * Created by anxpp.com on 2017/3/11.
 */
@Configuration
@EnableCaching
public class RedisCacheConfig {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.password}")
    private String password;
    @Bean
    public KeyGenerator csdnKeyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            for (Object obj : params) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }
    @Bean
    public JedisConnectionFactory redisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setHostName(host);
        factory.setPort(port);
        factory.setPassword(password);
        factory.setTimeout(timeout); //设置连接超时时间
        return factory;
    }
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        // Number of seconds before expiration. Defaults to unlimited (0)
        cacheManager.setDefaultExpiration(10); //设置key-value超时时间
        return cacheManager;
    }
    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate(factory);
        setSerializer(template); //设置序列化工具,这样ReportBean不需要实现Serializable接口
        template.afterPropertiesSet();
        return template;
    }
    private void setSerializer(StringRedisTemplate template) {
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);
    }
}

    如果我们有多个程序(甚至是不同语言编写的的),需要注意Redis的key和value的序列化机制,比如PHP和Java中使用Redis的默认序列化机制是不同的,如果不做配置,可能会导致两边存的数据互相取不出来。

    这样一来,就配置好了,后面直接使用就好。

3、网页解析抽象和csdnweekly实现

    首先定义网页解析接口:

package com.anxpp.tinysoft.Utils.analyzer;
import org.jsoup.nodes.Document;
import java.util.List;
import java.util.Map;
/**
 * 解析html文档抽象
 * Created by anxpp.com on 2017/3/11.
 */
public interface DocumentAnalyzer {
    /**
     * 根据html文档对象获取List<Map>
     * @param document html文档对象
     * @return 结果
     */
    List<Map<String,Object>> forListMap(Document document);
}

    针对csdn的每周干货推荐,编写具体实现:

package com.anxpp.tinysoft.Utils.analyzer.impl;
import com.anxpp.tinysoft.Utils.analyzer.DocumentAnalyzer;
import org.jsoup.nodes.Document;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 解析CSDN每周知识干货html文档具体实现
 * Created by anxpp.com on 2017/3/11.
 */
@Component
public class CsdnWeeklyDocumentAnalyzer implements DocumentAnalyzer {
    /**
     * 根据html文档对象获取List<Map>
     * @param document html文档对象
     * @return 结果
     */
    @Override
    public List<Map<String,Object>> forListMap(Document document) {
        List<Map<String,Object>> results = new ArrayList<>();
        if(ObjectUtils.isEmpty(document))
            return results;
        document.body().getElementsByClass("pclist").get(0).children().forEach(ele -> {
            Map<String,Object> result = new HashMap<>();
            result.put("type",ele.getElementsByTag("span").get(0).getElementsByTag("a").get(0).attr("href"));
            result.put("img",ele.getElementsByTag("span").get(0).getElementsByTag("a").get(0).getElementsByTag("img").get(0).attr("src"));
            result.put("url",ele.getElementsByTag("span").get(1).getElementsByTag("a").get(0).attr("href"));
            result.put("name",ele.getElementsByTag("span").get(1).getElementsByTag("a").get(0).text());
            result.put("views",Integer.valueOf(ele.getElementsByTag("span").get(1).getElementsByTag("span").get(0).getElementsByTag("em").get(0).text().replaceAll("\\D+","")));
            result.put("collections",Integer.valueOf(ele.getElementsByTag("span").get(1).getElementsByTag("span").get(1).getElementsByTag("em").get(0).text().replaceAll("\\D+","")));
            results.add(result);
        });
        return results;
    }
}

    当然,如果需要解析其他网页,实现DocumentAnalyzer接口,完成对应的解析方式也是完全可以的。

    然后,我们需要一个工具将Map转换为实体对象:

package com.anxpp.tinysoft.Utils;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
/**
 * 简单工具集合
 * Created by anxpp.com on 2017/3/11.
 */
class TinyUtil {
    /**
     * map转对象
     *
     * @param map  map
     * @param type 类型
     * @param <T>  泛型
     * @return 对象
     * @throws Exception 反射异常
     */
    static <T> T mapToBean(Map<String, Object> map, Class<T> type) throws Exception {
        if (map == null) {
            return null;
        }
        Set<Map.Entry<String, Object>> sets = map.entrySet();
        T entity = type.newInstance();
        Method[] methods = type.getDeclaredMethods();
        for (Map.Entry<String, Object> entry : sets) {
            String str = entry.getKey();
            String setMethod = "set" + str.substring(0, 1).toUpperCase() + str.substring(1);
            for (Method method : methods) {
                if (method.getName().equals(setMethod)) {
                    method.invoke(entity, entry.getValue());
                }
            }
        }
        return entity;
    }
}

    下面就是具体的数据获取逻辑了。

4、提供API以及数据获取逻辑

    首先我们需要定义一个实体:

package com.anxpp.tinysoft.core.entity;
import javax.persistence.*;
import java.util.Date;
/**
 * 文章信息
 * Created by anxpp.com on 2017/3/11.
 */
@Entity
@Table(name = "t_csdn_weekly_article")
public class Article extends BaseEntity{
    /**
     * 文章名称
     */
    private String name;
    /**
     * 文章名称
     */
    private String url;
    /**
     * 属于哪一期
     */
    private Integer stage;
    /**
     * 浏览量
     */
    private Integer views;
    /**
     * 收藏数
     */
    private Integer collections;
    /**
     * 所属知识库类别
     */
    private String type;
    /**
     * 类别图片地址
     */
    private String img;
    /**
     * 更新时间
     */
    @Column(name = "update_at", nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date updateAt;
    //省略get set 方法
}

    如果要持久化数据到数据库,也可以添加Repo层,使用Spring Data JPA也是超级方便的,博客中已提供相关文章参考,此处直接使用Redis,跳过此层。

    Service接口定义:

package com.anxpp.tinysoft.core.service;
import com.anxpp.tinysoft.core.entity.Article;
import java.util.List;
/**
 * 文章数据service
 * Created by anxpp.com on 2017/3/11.
 */
public interface ArticleService {
    /**
     * 根据期号获取文章列表
     * @param stage 期号
     * @return 文章列表
     */
    List<Article> forWeekly(Integer stage) throws Exception;
}

    Service实现:

package com.anxpp.tinysoft.core.service.impl;
import com.anxpp.tinysoft.Utils.ArticleSpider;
import com.anxpp.tinysoft.Utils.analyzer.impl.CsdnWeeklyDocumentAnalyzer;
import com.anxpp.tinysoft.core.entity.Article;
import com.anxpp.tinysoft.core.service.ArticleService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
 * 文章service实现
 * Created by anxpp.com on 2017/3/11.
 */
@Service
public class ArticleServiceImpl implements ArticleService {
    @Value("${csdn.weekly.preurl}")
    private String preUrl;
    @Resource
    private CsdnWeeklyDocumentAnalyzer csdnWeeklyDocumentAnalyzer;
    /**
     * 根据期号获取文章列表
     *
     * @param stage 期号
     * @return 文章列表
     */
    @Override
    @Cacheable(value = "reportcache", keyGenerator = "csdnKeyGenerator")
    public List<Article> forWeekly(Integer stage) throws Exception {
        List<Article> articleList = ArticleSpider.forEntityList(preUrl + stage, csdnWeeklyDocumentAnalyzer, Article.class);
        articleList.forEach(article -> article.setStage(stage));
        return articleList;
    }
}

    csdn.weekly.preurl为配置文件中配置的url前缀,后面会放出完整的配置文件。

    最后就是提供对外的接口,本文只添加了一个,也可以按需添加其他API:

package com.anxpp.tinysoft.controller;
import com.anxpp.tinysoft.core.entity.Article;
import com.anxpp.tinysoft.core.service.ArticleService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import java.util.List;
/**
 * 默认页面
 * Created by anxpp.com on 2017/3/11.
 */
@Controller
@RequestMapping("/article")
public class ArticleController {
    @Resource
    private ArticleService articleService;
    @ResponseBody
    @GetMapping("/get/stage/{stage}")
    public List<Article> getArticleByStage(@PathVariable("stage") Integer stage) throws Exception {
        return articleService.forWeekly(stage);
    }
}

    完整的配置文件:

server.port=****
#DataSource
spring.datasource.url=jdbc:mysql://****.***:****/****?createDatabaseIfNotExist=true
spring.datasource.username=****
spring.datasource.password=****
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#multiple Setting
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
#Redis
spring.redis.database=0
spring.redis.host=****
spring.redis.password=a****
spring.redis.pool.max-active=8
spring.redis.pool.max-idle=8
spring.redis.pool.max-wait=-1
spring.redis.pool.min-idle=0
spring.redis.port=****
#spring.redis.sentinel.master= # Name of Redis server.
#spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs.
spring.redis.timeout=0
#csdn setting
csdn.weekly.preurl=http://lib.csdn.net/weekly/

    数据库等的配置请根据实际情况配置。

    现在启动程序即可访问。

    

    源码已提交到GitHub:https://github.com/anxpp/csdnweeklySpider

    后续有时间会继续完善本程序添加更多网站内容的抓取。

]]>
0 http://blog.anxpp.com/index.php/archives/1057/#comments http://blog.anxpp.com/index.php/feed/archives/1057/
面试中Java可能涉及的知识点(E) http://blog.anxpp.com/index.php/archives/1052/ http://blog.anxpp.com/index.php/archives/1052/ Sun, 12 Feb 2017 02:24:00 +0000 anxpp 本文内容来自

  1. 同学、朋友、同事等的面试经历
  2. 互联网收集
  3. 书本

 

1、Java语言基础部分

    面向对象:封装、继承、多态

 

    基本数据类型及封装类型

 

    操作符及其优先级

 

    访问权限控制

 

    类、接口

 

    字符串

 

    泛型

 

    异常

    

 

 

2、Java容器部分

    Collection

 

 

    Map

 

 

    Concurrent包下的容器

 

 

 

3、Java多线程部分

    基础及概念

 

 

    线程池

 

 

    并发中的资源共享

    

 

 

 

4、Java IO部分

     网络IO详见:http://blog.anxpp.com/index.php/archives/895/

 

 

 

 

5、JVM部分

    内存区域

 

 

    GC

 

 

    参数调优

 

 

 

 6、其他库的使用

     lang3等

 

 

]]>
0 http://blog.anxpp.com/index.php/archives/1052/#comments http://blog.anxpp.com/index.php/feed/archives/1052/
面试中Spring可能涉及的知识点 http://blog.anxpp.com/index.php/archives/1040/ http://blog.anxpp.com/index.php/archives/1040/ Mon, 06 Feb 2017 13:52:00 +0000 anxpp 本文内容来自

  1. 同学、朋友、同事等的面试经历
  2. 互联网收集
  3. 书本

    

1、什么是Spring框架?Spring框架有哪些主要模块?

    Spring框架是一个为Java应用程序的开发提供了综合、广泛的基础性支持的Java平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。Spring框架本身亦是按照设计模式精心打造,这使得我们可以在开发环境中安心的集成Spring框架,不必担心Spring是如何在后台进行工作的。

    Spring框架至今已集成了几十个模块。这些模块主要被分为核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。

    相关框架:简化数据访问的Spring Data、面向微服务的Spring Boot、简化Web开发的Spring MVC等。

    详见:http://spring.io/projects

2、Spring框架的好处

  • 轻量:Spring 是轻量的,基本的版本大约2MB。
  • 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
  • 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
  • 容器:Spring 包含并管理应用中对象的生命周期和配置。
  • MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
  • 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
  • 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,hibernate or JDO抛出的)转化为一致的unchecked 异常。

3、什么是控制反转(IOC)?什么是依赖注入?

    在传统的编程方式中,业务逻辑的流程是由应用程序中的早已被设定好关联关系的对象来决定的。在使用控制反转的情况下,业务逻辑的流程是由对象关系图来决定的,该对象关系图由装配器负责实例化,这种实现方式还可以将对象之间的关联关系的定义抽象化。而绑定的过程是通过“依赖注入”实现的。

    控制反转是一种以给予应用程序中目标组件更多控制为目的设计范式,并在我们的实际工作中起到了有效的作用。

    依赖注入是在编译阶段尚未知所需的功能是来自哪个的类的情况下,将其他对象所依赖的功能对象实例化的模式。这就需要一种机制用来激活相应的组件以提供特定的功能,所以依赖注入是控制反转的基础。否则如果在组件不受框架控制的情况下,框架又怎么知道要创建哪个组件?

    在Java中依然注入有以下三种实现方式:构造器注入、Setter方法注入、接口注入;

4、解释Spring框架中的IoC

    IOC即控制反转,Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

    谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

    为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

5、Spring有几种配置方式?

    将Spring配置到应用开发中有以下三种方式:基于XML的配置、基于注解的配置、基于Java的配置;

6、什么是bean装配?什么是bean的自动装配?自动装配有哪些方式?自动装配有哪些局限性 ?

    装配(bean 装配)是指在Spring 容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。

    Spring 容器能够自动装配相互合作的bean,这意味着容器不需要<constructor-arg>和<property>配置,能通过Bean工厂自动处理bean之间的协作。

    有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。:

  • no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
  • byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
  • byType:通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
  • constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
  • autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。

    自动装配的局限性是:

  • 重写: 你仍需用 <constructor-arg>和 <property> 配置来定义依赖,意味着总要重写自动装配。
  • 基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
  • 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。

7、可以在Spring中注入一个null 和一个空字符串吗?

    可以。

8、介绍Spring的事务管理

    Spring的事务管理分为声明式跟编程式。

    声明式就是在Spring的配置文件中进行相关配置;编程式就是用使用TransactionTemplate和直接使用PlatformTransactionManager方式写到代码里。

    声明式: Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。 DataSource、 TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为 SessionFactory,TransactionManager的实现为HibernateTransactionManager。 

9、Spring 声明式事务的配置方式有哪几种

  • 使用tx标签
  • 使用代理方式
  • 使用拦截器
  • 全注解

    配置方式:

<!-- 第一种配置事务的方式 ,tx-->
<tx:advice id="txadvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="*" propagation="REQUIRED" read-only="true"/>
    </tx:attributes>
</tx:advice>
<aop:config>
    <aop:pointcut id="daoMethod" expression="execution(* com.dao.*.*(..))"/>
    <aop:advisor pointcut-ref="daoMethod" advice-ref="txadvice"/>
</aop:config>
<!-- -->
<!-- 第二种配置事务的方式 ,代理-->
<bean id="transactionProxy"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"    abstract="true">
    <property name="transactionManager" ref="transactionManager"></property>
    <property name="transactionAttributes">
        <props>
            <prop key="add*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
        </props>
    </property>
</bean>
<bean id="userDao" parent="transactionProxy">
    <property name="target">
        <!-- 用bean代替ref的方式-->
        <bean class="com.dao.UserDaoImpl">
            <property name="sessionFactory" ref="sessionFactory"></property>
        </bean>
    </property>
</bean>
<!-- -->
<!-- 第三种配置事务的方式,拦截器 (不常用)-->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"></property>
    <property name="transactionAttributes">
        <props>
            <prop key="add*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
        </props>
    </property>
</bean>
<bean id="proxyFactory" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="interceptorNames">
        <list>
            <value>transactionInterceptor</value>
        </list>
    </property>
    <property name="beanNames">
        <list>
            <value>*Dao</value>
        </list>
    </property>
</bean>
    <!--注解-->
<context:annotation-config /> <context:component-scan base-package="com.bluesky" /> <tx:annotation-driven transaction-manager="transactionManager"/> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> </bean> <!-- 定义事务管理器(声明式的事务) --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>

10、Spring有哪些事务类型(传播方式)?

    事务的第一个方面是传播行为(propagation behavior)。

    当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。Spring定义了七种传播行为:

  1. PROPAGATION_REQUIRED 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
  2. PROPAGATION_SUPPORTS 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
  3. PROPAGATION_MANDATORY 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
  4. PROPAGATION_REQUIRED_NEW 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
  5. PROPAGATION_NOT_SUPPORTED 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
  6. PROPAGATION_NEVER 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
  7. PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务

11、Spring与Spring MVC容器中的bean可以共享吗?

     Spring和Spring MVC两个都是bean的容器,Spring是根容器,SpringMVC是其子容器,并且在Spring根容器中对于SpringMVC容器中的Bean是不可见的,而在SpringMVC容器中对于Spring根容器中的Bean是可见的,也就是子容器可以看见父容器中的注册的Bean(但是如果不额外配置默认不检测父容器的bean),反之就不行(参考类的继承机制这很好理解)。

    当我们使用注解时,对于Bean注册这个功能的实现就不需要在给每个Bean配置XML了,只要使用统一的如下配置即可:

<context:component-scan base-package="com.***" />

    根据Spring提供的参考手册,该配置的功能是扫描默认包下的所有的@Component注解,并且自动注册到容器中,同时也扫描@Controller,@Service,@Respository这三个注解,他们是继承自@Component。

    除了以上我们使用的扫描配置,在项目中我们经常见到的就是<context:annotation-config/>这个配置,其实有了以上的配置,这个是可以省略掉的。

    还有一个SpringMVC相关的是<mvc:annotation-driven />配置,而且这是必须的,因为Spring MVC中很多注解是Spring中没有的!

    HandlerMapping,是SpringMVC中用来处理Request请求URL到具体Controller的,其自身也分成很多种类; HandlerAdapter,是SpringMVC中用来处理具体请求映射到具体方法的,其自身也分很多种类; @RequestMapping这个注解的主要目的就是对具体的Controller和方法进行注册,以方便HandlerMapping用来处理请求的映射。但是@RequestMapping需要结合<mvc:annotation-driven />使用才能生效。

12、

 

 

 

 

 

 

]]>
0 http://blog.anxpp.com/index.php/archives/1040/#comments http://blog.anxpp.com/index.php/feed/archives/1040/
Ubuntu 16.04下安装ssh远程无法连接的解决方法 http://blog.anxpp.com/index.php/archives/1039/ http://blog.anxpp.com/index.php/archives/1039/ Thu, 19 Jan 2017 14:43:09 +0000 anxpp     因为新版的ssh抛弃了以前的加密算法,所以ssh客户端不能连接,请求会被拒绝,我们可以指定原来的加密算法即可。

    打开配置文件:

sudo vi /etc/ssh/sshd_config

    在最后添加如下内容(命令模式按shift+g跳到最后一行,然后按小写的o新起一行):

Ciphers aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,3des-cbc,arcfour128,arcfour256,arcfour,blowfish-cbc,cast128-cbc  
MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160,hmac-sha1-96,hmac-md5-96  
KexAlgorithms diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group-exchange-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group1-sha1,curve25519-sha256@libssh.org  

    完成后重启ssh即可连接:

sudo /etc/init.d/ssh restart 

    如果需要root用户远程登录,还需要修改配置文件:

PermitRootLogin without-password

   改为:

PermitRootLogin yes

    然后重启ssh即可。

]]>
0 http://blog.anxpp.com/index.php/archives/1039/#comments http://blog.anxpp.com/index.php/feed/archives/1039/