饭饭's Blog - 2019年
type: channel
link: https://ffis.me/2019/
description: 饭饭的博客（ffis.me） - 不忘初心，方得始终
items: Centos下使用shell脚本来批量管理Spring Boot Api服务
items: 念念不忘，必有回响，心仪的域名终于注册成功辣~
items: 博客的友情链接从首页移至内页啦
items: 解决Spring项目打成Jar包后Freemarker找不到模板的问题
items: 自己动手造了个监控域名可否注册的Api → CheckDomain
items: 记一次解决RestTemplate无法解析api返回的xml数据问题
items: Docker的基本操作与使用
items: Git分布式版本控制工具
items: mybatis03 - 多表查询、简单的SSM整合
items: mybatis02 - 核心配置文件深入

Centos下使用shell脚本来批量管理Spring Boot Api服务
type: item
date: 2019-12-30T21:26:00+08:00
description: 前言最近在部署Spring Boot构建的Api因为有多个jar要启动，启动的参数也都不一样 搞的我都蛋疼了，只好研究下使用shell脚本来一键管理了花了两个小时，终于把脚本撸出来了 注意如果在windows下创建shell脚本文件，注意文档格式要转换为unix才能在linux中运行推荐直接在linux中直接使用vi创建shell脚本文件创建脚本在指定路径下运行vi startAll.sh来创建脚本文件参考如下代码：#!/bin/sh ## java安装目录 export JAVA_HOME=/usr/java/jdk1.8 export JRE_HOME=$JAVA_HOME/jre # 端口号 PORTS=(7077 7078) # 模块 MODULES=(api-1 api-2) # 模块名称 MODULE_NAMES=(测试-1 测试-2) # jar包数组 JARS=(xxx1.jar xxx2.jar) # jar包路径 JAR_PATH='/data/test' # 日志路径 LOG_PATH='/data/test/logs' # 启动方法 start() { echo "----------启动服务----------" local MODULE= local MODULE_NAME= local JAR_NAME= local command="$1" local commandOk=0 local count=0 local okCount=0 local port=0 for((i=0;i<${#MODULES[@]};i++)) do MODULE=${MODULES[$i]} MODULE_NAME=${MODULE_NAMES[$i]} JAR_NAME=${JARS[$i]} PORT=${PORTS[$i]} if [ "$command" == "all" ] || [ "$command" == "$MODULE" ];then commandOk=1 count=0 if [ ! -d $LOG_PATH ];then mkdir $LOG_PATH fi PID=`ps -ef |grep $(echo $JAR_NAME | awk -F/ '{print $NF}') | grep -v grep | awk '{print $2}'` if [ -n "$PID" ];then echo "$MODULE---$MODULE_NAME:已经运行,PID=$PID" else #这行命令根据自己的需要更改 cd $JAR_PATH && nohup $JRE_HOME/bin/java -Xms256m -Xmx512m -jar $JAR_NAME --spring.config.location=config/application.yml --server.port=$PORT >> $LOG_PATH/$MODULE.log 2>&1 & PID=`ps -ef |grep $(echo $JAR_NAME | awk -F/ '{print $NF}') | grep -v grep | awk '{print $2}'` while [ -z "$PID" ] do if (($count == 10));then echo "$MODULE---$MODULE_NAME:$(expr $count \* 10)秒内未启动,请检查!" break fi count=$(($count+1)) echo "$MODULE_NAME启动中..." sleep 10s PID=`ps -ef |grep $(echo $JAR_NAME | awk -F/ '{print $NF}') | grep -v grep | awk '{print $2}'` done okCount=$(($okCount+1)) echo "$MODULE---$MODULE_NAME:已经启动成功,PID=$PID" fi fi done if(($commandOk == 0));then echo "第二个参数输入错误" else echo "----本次共启动:$okCount个服务----" fi } # 停止方法 stop() { echo "----------停止服务----------" local MODULE= local MODULE_NAME= local JAR_NAME= local command="$1" local commandOk=0 local okCount=0 for((i=0;i<${#MODULES[@]};i++)) do MODULE=${…

念念不忘，必有回响，心仪的域名终于注册成功辣~
type: item
date: 2019-12-29T22:44:00+08:00
description: 前些天看中了一个域名，是由我的名字简写的域名 fanhy.com，正处于赎回期，原注册者也不打算赎回了 于是就写了个监控域名注册的Api来监控该域名，等域名可以注册了就给我发送邮件通知 传送门：自己动手造了个监控域名可否注册的Api → CheckDomain经过半个多月的等待，终于在今日凌晨，该域名终于被注册局删除 由于我早就推算好时间，今天睡觉的时候就给邮件通知加上了铃声通知，于是凌晨3点左右就收到了域名可以注册的邮件梦中惊醒，打开早就准备好的注册页面，下单，付款一气呵成，域名终于到手！ 开心~~~ 不过注册后了才发现是一时冲动，手上已经有两个域名了，拿这个域名干什么呢？ 不管这么多了，先拿去备案再说吧~网站备案期间需要暂时关闭留言功能...

博客的友情链接从首页移至内页啦
type: item
date: 2019-12-12T23:56:00+08:00
description: 由于友情链接日益增多已经影响阅读，风格也过于单调 所以就抽了个时间把友链从首页移动到内页这样就能给友链加特效啦 友链的风格设计 参考了 基本照抄了：https://logi.ml/添加了头像的展示，效果如下：没有头像的小伙伴们还不快给我留言添加头像~~~

解决Spring项目打成Jar包后Freemarker找不到模板的问题
type: item
date: 2019-12-11T23:33:00+08:00
description: 昨天改完CheckDomain的bug后，打包jar准备部署到服务器上，本地测试都正常，但是扔到服务器上却发不了邮件了... 经过多次测试发现，freemarker在jar包中无法使用类加载器获取resourse目录下的templates文件 出现的问题代码如下：（本地测试正常，打包jar后无法获取模板）/** * 邮件模板静态化 * * @param mailTemplateModel 模板数据模型 * @return 加上数据后的静态化模板 */ @Override public String getMailHtml(MailTemplateModel mailTemplateModel) { try { //创建配置类 Configuration configuration = new Configuration(Configuration.getVersion()); //设置模板路径 String classpath = this.getClass().getResource("/").getPath(); configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates")); //设置字符集 configuration.setDefaultEncoding("utf-8"); //加载模板 Template template = configuration.getTemplate("mailTemplate.ftl"); //模板静态化并返回 return FreeMarkerTemplateUtils.processTemplateIntoString(template, mailTemplateModel); } catch (Exception e) { e.printStackTrace(); log.error("模板静态化异常", e); return null; } }修改后的代码：（打包jar后正常获取模板）@Autowired FreeMarkerConfigurer freeMarkerConfigurer; /** * 邮件模板静态化 * * @param mailTemplateModel 模板数据模型 * @return 加上数据后的静态化模板 */ @Override public String getMailHtml(MailTemplateModel mailTemplateModel) { try { //创建配置类 Configuration configuration = new Configuration(Configuration.getVersion()); //设置模板路径 //String classpath = this.getClass().getResource("/").getPath(); //configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates")); //设置字符集 configuration.setDefaultEncoding("utf-8"); //加载模板 //Template template = configuration.getTemplate("mailTemplate.ftl"); Template template = freeMarkerConfigurer.getConfiguration().getTemplate("mailTemplate.ftl"); //模板静态化并返回 return FreeMarkerTemplateUtils.processTemplateIntoString(template, mailTemplateModel); } catch (Exception e) { e.printStackTrace(); log.error("模板静态化异常", e); return null; } }PS: .ftl模板文件放在 templates 目录下总结：freemarker无法使用类加载器获取jar包中的resourse目录下的templates文件解决办法：注入FreeMarkerConfigurer配置类，因为freemarker模板的默认目录就在resourse下的templates目录下，使用freeMarkerConfigurer.getConfiguration().getTemplate("mailTemplate.ftl")可直接获取到对应的模板文件

自己动手造了个监控域名可否注册的Api → CheckDomain
type: item
date: 2019-12-07T23:17:00+08:00
description: 前两天我看中了一个域名处于即将删除的状态 ，想着如果能监控域名能注册了给我发邮件就好了，于是就花了一晚上撸出了 CheckDomain 来帮我监控这个域名 。CheckDomain 是一个用来检查域名是否能注册的 Api，基于 Spring Boot 构建，使用了阿里云域名查询 Api；可实现对域名状态查询，可注册监控等，并在可以注册的时候发送邮件通知。也算是自己动手做的第一个完整的项目吧 既然有了兴趣点，所以就准备把所学的知识给串一下，能用上的都用上，也算是学以致用吧~ Github：https://github.com/noisky/CheckDomainDemo：https://whois.ffis.me接口调用：1、查看域名状态：请求方式：GET请求请求地址：/domain/{name}参数说明：{name}： 查询的域名2、查看域名状态并在可注册时发送邮件通知：1）请求方式：GET请求请求地址：/domain/{name}/{email}/{querykey}参数说明：{name}： 查询的域名{email}： 接受通知的邮箱地址querykey： 查询密码，在 yml 配置文件中设置2）请求方式：POST请求请求地址：/domain/{name}参数说明：{name}： 查询的域名POST 提交的表单：email： 接受通知的邮箱地址querykey： 查询密码，在 yml 配置文件中设置可以使用第三方监控（如阿里云监控）来请求 Api 来达到监控域名注册状态现在已经实现了基本功能：检查域名是否能注册监控域名状态，如果可以注册，发送邮件通知使用 Freemarker 实现邮件模板的静态化使用 Logback 记录系统运行日志实现域名的 whois 信息查询（参考了 tammypi 的 whoisutil 工具类）已完成编写前端页面，现在可以直接在页面上查询 whois 信息了TODO：限制接口的调用频率统计并记录接口的调用次数，调用耗时等信息...使用了万网域名查询接口（已经自己实现直接向whois服务器查询信息）：接口地址：http://panda.www.net.cn/cgi-bin/check.cgi接口采用HTTP，POST，GET协议参数名称：area_domain 值为标准域名，例：xxx.com返回 XML 结果说明：返回字段说明200表示接口返回成功xxx.com表示当前检查的域名210Domain name is available 表示域名可以注册211Domain name is not available 表示域名已经注册212Domain name is invalid 表示域名参数传输错误213Time out 查询超时注意：这个接口返回的数据虽然看起来是xml格式，但是响应头却是 text/plain 格式的，搞的我踩了好多深坑...详见：记一次解决RestTemplate无法解析api返回的xml数据问题

记一次解决RestTemplate无法解析api返回的xml数据问题
type: item
date: 2019-12-06T21:52:00+08:00
description: 最近看上了个本命域名，因为过期即将被注册局删除，于是就自己写了个api接口用来监控这个域名，等可以注册了就直接发邮件通知我 其中用到了阿里云域名的一个api，准备直接使用RestTemplate去请求这个接口，并将结果自动封装为Map集合方便进行进一步处理。等到框架搭好，代码写完，以为万事大吉的时候，程序却给我来了个惊喜： org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [text/plain;charset=GBK]很明显，上面提示接口返回的是text/plain文本类型数据，RestTemplate解析数据的时候没有找到合适的解析器，就抛了异常。WTF？ 我看阿里云的接口明明返回的是xml的数据啊......仔细再定睛一看，类型还真的是文本类型...我嘞个去，还有这种操作？ 这可怎么办？当时我没想太多，就直接将返回值保存为String类型，然后使用jackson直接解析成对象了，这样也能进行数据处理了;不过问题虽然暂时解决了，可终究不是好办法，RestTemplate本身就内置了jackson解析器，所以说肯定能直接让RestTemplate解析这个数据的;本着极客精神，今天有空就看了下源码：根据程序提示的异常信息：org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [text/plain;charset=GBK] at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:123) at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1001) at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:984)先进入HttpMessageConverterExtractor.java中，于是看到如下逻辑HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var4.next(); if (messageConverter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter)messageConverter; if (genericMessageConverter.canRead(this.responseType, (Class)null, contentType)) { if (this.logger.isDebugEnabled()) { ResolvableType resolvableType = ResolvableType.forType(this.responseType); this.logger.debug("Reading to [" + resolvableType + "]"); } return genericMessageConverter.read(this.responseType, (Class)null, responseWrapper); } } if (this.responseClass != null && messageConverter.canRead(this.responseClass, contentType)) { if (this.logger.isDebugEnabled()) { String cl…

Docker的基本操作与使用
type: item
date: 2019-11-21T22:53:00+08:00
description: 1 Docker简介Docker 是一个开源的应用容器引擎，基于 Go 语言开发。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中，然后发布到任何流行的 Linux 机器上，也可以实现虚拟化。容器是完全使用沙箱机制，相互之间不会有任何接口（类似 iPhone 的 app）,更重要的是容器性能开销极低。Docker应用场景Web应用的自动化打包和发布自动化测试和持续集成、发布在服务型环境中部署和调整数据库或其他的后台应用简单的说：使用Docker可以实现开发人员的开发环境、测试人员的测试环境、运维人员的生产环境的一致性。Docker借鉴了标准集装箱的概念。标准集装箱将货物运往世界各地，Docker将这个模型运用到自己的设计中，唯一不同的是：集装箱运输货物，而Docker运输软件。Docker组成部分名称说明Docker 镜像(Images)Docker 镜像是用于创建 Docker 容器的模板。 镜像是基于联合文件系统的一种层式结构，由一系列指令一步一步构建出来。Docker 容器(Container)容器是独立运行的一个或一组应用。镜像相当于类，容器相当于类的实例Docker 客户端(Client)Docker 客户端通过命令行或者其他工具使用 Docker API 与 Docker 的守护进程通信。Docker 主机(Host)一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。Docker守护进程是Docker服务器端进程，负责支撑Docker 容器的运行以及镜像的管理。Docker 仓库DockerHub(Registry)Docker 仓库用来保存镜像，可以理解为代码控制中的代码仓库。 Docker Hub提供了庞大的镜像集合供使用。用户也可以将自己本地的镜像推送到Docker仓库供其他人下载。2 Docker安装与启动2.1 Dockek安装Docker可以运行在MAC、Windows、CentOS、DEBIAN、UBUNTU等操作系统上，提供社区版和企业版下面在centos7中安装Docker# 1、yum 包更新到最新 sudo yum update # 2、作用：安装需要的软件包， yum-util 提供yum-config-manager功能，另外两个是devicemapper驱动依 赖的 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 # 3、 设置yum源 # 3.1、方案一：使用ustc的 sudo yum-config-manager --add-repo http://mirrors.ustc.edu.cn/dockerce/ linux/centos/docker-ce.repo # 3.2、方案二：使用阿里云 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/dockerce/ linux/centos/docker-ce.repo # 4、 安装docker；出现输入的界面都按 y sudo yum install -y docker-ce # 5、 查看docker版本 docker -v2.2 设置USTC镜像ustc是老牌的linux镜像服务提供者了，还在遥远的ubuntu 5.04版本的时候就在用。ustc的docker镜像加速器速度很快。ustc docker mirror的优势之一就是不需要注册，是真正的公共服务https://lug.ustc.edu.cn/wiki/mirrors/help/docker1、 编辑文件/etc/docker/daemon.json# 执行如下命令： mkdir /etc/docker vi /etc/docker/daemon.json2、在文件中加入下面内容{ "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"] }2.3 Docker启动与停止命令# 启动docker服务： systemctl start docker # 停止docker服务： systemctl stop docker # 重启docker服务： systemctl restart docker # 查看docker服务状态： systemctl status docker # 设置开机启动docker服务： systemctl enable docker3 Docker常用命令3.1. 镜像相关命令镜像：Docker镜像是由文件系统叠加而成（是一种文件的存储形式）；是docker中的核心概念，可以认为镜像就是对某些运…

Git分布式版本控制工具
type: item
date: 2019-10-27T20:30:04+08:00
description: 1 Git概述1.1 Git历史Git 诞生于一个极富纷争大举创新的年代。Linux 内核开源项目有着为数众多的参与者。 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上（1991－2002年间）。 到 2002 年，整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。到了 2005 年，开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束，他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 这就迫使 Linux 开源社区（特别是 Linux 的缔造者 Linus Torvalds）基于使用 BitKeeper 时的经验教训，开发出自己的版本系统。 他们对新的系统制订了若干目标：速度简单的设计对非线性开发模式的强力支持（允许成千上万个并行开发的分支）完全分布式有能力高效管理类似 Linux 内核一样的超大规模项目（速度和数据量）1.2 Git与SVN对比SVN是集中式版本控制系统，版本库是集中放在中央服务器的，而开发人员工作的时候，用的都是自己的电脑，所以首先要从中央服务器下载最新的版本，然后开发，开发完后，需要把自己开发的代码提交到中央服务器。集中式版本控制工具缺点：服务器单点故障容错性差Git是分布式版本控制系统（Distributed Version Control System，简称 DVCS） ，分为两种类型的仓库：本地仓库和远程仓库本地仓库：是在开发人员自己电脑上的Git仓库 远程仓库：是在远程服务器上的Git仓库Clone：克隆，就是将远程仓库复制到本地Push：推送，就是将本地仓库代码上传到远程仓库Pull：拉取，就是将远程仓库代码下载到本地仓库1.3 Git工作流程工作流程如下：1．从远程仓库中克隆代码到本地仓库2．从本地仓库中checkout代码然后进行代码修改3．在提交前先将代码提交到暂存区4．提交到本地仓库。本地仓库中保存修改的各个历史版本5．修改完成后，需要和团队成员共享代码时，将代码push到远程仓库1.4 Git下载与安装下载地址： https://git-scm.com/download安装过程详见：https://ffis.me/experience/1441.html2 Git代码托管服务2.1 常用的Git代码托管服务前面已经知道了Git中存在两种类型的仓库，即本地仓库和远程仓库。那么我们如何搭建Git远程仓库呢？我们可以借助互联网上提供的一些代码托管服务来实现，其中比较常用的有GitHub、码云、GitLab等。Github（ 地址：https://github.com/ ）是一个面向开源及私有软件项目的托管平台，因为只支持Git 作为唯一的版本库格式进行托管，故名Github码云（地址： https://gitee.com/ ）是国内的一个代码托管平台，由于服务器在国内，所以相比于GitHub，码云速度会更快GitLab （地址： https://about.gitlab.com/ ）是一个用于仓库管理系统的开源项目，使用Git作为代码管理工具，并在此基础上搭建起来的web服务2.2 在码云注册账号要想使用码云的相关服务，需要注册账号（地址： https://gitee.com/signup ）2.3 登录码云并创建Git远程仓库注册完成后就可以使用刚刚注册的邮箱进行登录（地址： https://gitee.com/login ）登录成功后就可以创建Git远程仓库创建完成后可以查看仓库信息每个Git远程仓库都会对应一个网络地址，可以点击克隆/下载按钮弹出窗口并点击复制按钮获得这个网络地址当前创建的Git远程仓库对应的地址为：https://gitee.com/noisky/myRepo.git2.4 邀请其他用户成为仓库成员前面已经在码云上创建了自己的远程仓库，目前仓库成员只有自己一个人（身份为管理员）。在企业实际开发中，一个项目往往是由多个人共同开发完成的，为了使多个参与者都有权限操作远程仓库，就需要邀请其他项目参与者成为当前仓库的成员。3 Git常用命令3.1 环境配置当安装Git后首先要做的事情是设置用户名称和email地址。这是非常重要的，因为每次Git提交都会使用该用户信息设置用户信息 git config --global user.name “noisky”git config --global user.email “xxx@ffis.me”查看配置信息git config --listgit config user.name通过上面的命令设置的信息会保存在~/.gitconfig（用户目录下）文件中3.2 获取Git仓库要使用Git对我们的代码进行版本控制，首先需…

mybatis03 - 多表查询、简单的SSM整合
type: item
date: 2019-10-21T20:50:24+08:00
description: 1 Mybatis多表查询1.1 一对一查询1.1.1 一对一查询的模型用户表和订单表的关系为，一个用户有多个订单，一个订单只从属于一个用户一对一查询的需求：查询一个订单，与此同时查询出该订单所属的用户1.1.2一对一查询的语句对应的sql语句：SELECT *,o.id oid FROM orders o, USER u WHERE o.uid = u.id;查询的结果如下：1.1.3 创建Order和User实体public class Order { private int id; private Date ordertime; private double total; //代表当前订单从属于哪一个客户 private User user; //此处省略getter和setter } public class User { private int id; private String username; private String password; private Date birthday; //此处省略getter和setter }1.1.4 创建OrderMapper接口public interface OrderMapper { List<Order> findAll(); }1.1.5 配置OrderMapper.xml<mapper namespace="me.ffis.mapper.OrderMapper"> <resultMap id="orderMap" type="me.ffis.domain.Order"> <result column="uid" property="user.id"></result> <result column="username" property="user.username"></result> <result column="password" property="user.password"></result> <result column="birthday" property="user.birthday"></result> </resultMap> SELECT *,o.id oid FROM orders o, USER u WHERE o.uid = u.id </mapper>其中还可以配置如下：<resultMap id="orderMap" type="me.ffis.domain.Order"> <result property="id" column="id"></result> <result property="ordertime" column="ordertime"></result> <result property="total" column="total"></result> <association property="user" javaType="me.ffis.domain.User"> <result column="uid" property="id"></result> <result column="username" property="username"></result> <result column="password" property="password"></result> <result column="birthday" property="birthday"></result> </association> </resultMap>1.1.6 测试结果OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); List<Order> all = mapper.findAll(); for(Order order : all){ System.out.println(order); }1.2 一对多查询1.2.1 一对多查询的模型用户表和订单表的关系为，一个用户有多个订单，一个订单只从属于一个用户一对多查询的需求：查询一个用户，与此同时查询出该用户具有的订单1.2.2 一对多查询的语句对应的sql语句：SELECT *,o.id oid FROM USER u, orders o WHERE u.id = o.uid;查询的结果如下：1.2.3 修改User实体public class Order { private int id; private Date ordertime; private double total; //代表当前订单从属于哪一个客户 private User user; //此处省略getter和set…

mybatis02 - 核心配置文件深入
type: item
date: 2019-10-20T21:03:00+08:00
description: 1 Mybatis的Dao层实现1.1 传统开发方式1.1.1 编写UserDao接口public interface UserDao { List<User> findAll() throws IOException; }1.1.2 编写UserDaoImpl实现public class UserDaoImpl implements UserDao { public List<User> findAll() throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> userList = sqlSession.selectList("userMapper.findAll"); sqlSession.close(); return userList; } }1.1.3 测试传统方式@Test public void testTraditionDao() throws IOException { UserDao userDao = new UserDaoImpl(); List<User> all = userDao.findAll(); System.out.println(all); }1.2 代理开发方式1.2.1 代理开发方式介绍采用 Mybatis 的代理开发方式实现 DAO 层的开发，这种方式是我们后面进入企业的主流。Mapper 接口开发方法只需要程序员编写Mapper 接口（相当于Dao 接口），由Mybatis 框架根据接口定义创建接口的动态代理对象，代理对象的方法体同上边Dao接口实现类方法。Mapper 接口开发需要遵循以下规范：1) Mapper.xml文件中的namespace与mapper接口的全限定名相同2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同4) Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同1.2.2 编写UserMapper接口1.2.3 测试代理方式@Test public void testProxyDao() throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); //获得MyBatis框架生成的UserMapper接口的实现类 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.findById(1); System.out.println(user); sqlSession.close(); }1.3 知识小结MyBatis的Dao层实现的两种方式：手动对Dao进行实现：传统开发方式代理方式对Dao进行实现： **UserMapper userMapper = sqlSession.getMapper(UserMapper.class);** 2 MyBatis映射文件深入2.1 动态sql语句2.1.1 动态sql语句概述Mybatis 的映射文件中，前面我们的 SQL 都是比较简单的，有些时候业务逻辑复杂时，我们的 SQL是动态变化的，此时我们的 SQL 就不能满足要求了。参考的官方文档，描述如下：2.1.2 动态 SQL 之<if>我们根据实体类的不同取值，使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询，如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。 …