Ubuntu禁用Systemd解析

主机安装Ubuntu 18.04,在hosts中配置了开发时使用的域名。想把主机做为DNS服务器,供路由器使用,这样网内的机器不需要指定DNS就能解析了。

在Linux以前的版本,只需要安装bind或dnsmasq,把监听地址改为网卡地址,网内的机器就能使用。

DNS服务软件我使用的是dnsmasq,使用apt源安装,启动服务失败。查看原因:

原来53端口被占用。

Ubuntu 18.04变化还是挺多的,比如设置hostname,不能再简单修改/etc/hostname。Ubuntu 18.04桌面版,新增了一个systemd-resolved服务,禁用它就好。

继续阅读“Ubuntu禁用Systemd解析”

Spring 过滤危险字符

项目中涉及到复杂查询,比如模糊查询。ORM框架往往不能很好处理,难免会遇到拼接字符串。而手动拼接的方式很容易让代码产生SQL注入漏洞。使用拦截器和过滤器,过滤请求中的危险字符,可以解决SQL注入攻击。

常用的请求有两种方式,一种是form表单提交,另一种是json格式。在Spring框架中处理这两种的方法也是有区别的。

过滤form表单

过滤表单提交的危险字符,使用的是过滤器,需要继承OncePerRequestFilter类。

在spring中,filter都默认继承OncePerRequestFilter。顾名思义,他能够确保在一次请求只通过一次filter,而不需要重复执行。

大家常识上都认为,一次请求本来就只过一次,为什么还要由此特别限定呢,实际上我们常识和实际的实现并不真的一样,经过一番查阅后,此方式是为了兼容不同的web container,特意而为之(jsr168),也就是说并不是所有的container都像我们期望的只过滤一次,servlet版本不同,表现也不同。

/**
* Filter base class that guarantees to be just executed once per request,
* on any servlet container. It provides a {@link #doFilterInternal}
* method with HttpServletRequest and HttpServletResponse arguments.
*
* <p>The {@link #getAlreadyFilteredAttributeName} method determines how
* to identify that a request is already filtered. The default implementation
* is based on the configured name of the concrete filter instance.
*
* @author Juergen Hoeller
* @since 06.12.2003
*/

如,servlet2.3与servlet2.4也有一定差异

在servlet-2.3中,Filter会过滤一切请求,包括服务器内部使用forward转发请求和<%@ include file="/index.jsp"%>的情况。
到了servlet-2.4中Filter默认下只拦截外部提交的请求,forward和include这些内部转发都不会被过滤,但是有时候我们需要 forward的时候也用到Filter。

因此,为了兼容各种不同的运行环境和版本,默认filter继承OncePerRequestFilter是一个比较稳妥的选择。

以下是我的过滤器代码:

继续阅读“Spring 过滤危险字符”

Maven引入第三方Jar

不是每个第三方jar都要交给Maven库管理。在开发中,常常会引用第三方库,放在WEB-INF/lib下发布。在Maven中,可以用以下方法引入这些Jar管理。

<dependency>
	<groupId>cn.payadd.dao</groupId>
	<artifactId>dao</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<scope>system</scope>
	<systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/dao-20190516.jar</systemPath>
</dependency>

打成war包时在build中加入jar资源路径

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-war-plugin</artifactId>
	<configuration>
		<webResources>
			<resource>
				<directory>src/main/webapp/WEB-INF/lib/</directory>
				<targetPath>WEB-INF/lib/</targetPath>
				<includes>
					<include>**/*.jar</include>
				</includes>
			</resource>
		</webResources>
	</configuration>
</plugin>

参考: https://blog.csdn.net/zhuyongzhen1219/article/details/79217986

Cause: java.sql.SQLException: Zero date value prohibited

使用MySQL 8.0驱动连接数据库,执行操作,抛出异常:

这是由于createDate字段值引起。该表中某些数据未指定正确的日期。

解决办法:

1.修正数据,指定createDate值

2.在驱动连接加上参数:&zeroDateTimeBehavior=convertToNull

我使用的是第二种方式,驱动url为:

jdbc:mysql://10.243.3.18:3306/gbd?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull

旧版驱动没有这个问题,应该是新版驱动增加了更严格的校验。

养鱼记

自从5月14号买的两条金鱼翻肚皮后,好强的baby开始认真起来。网购一条“狮王”,卖家发错货,寄来一条蓝色的“马尾”。看着也挺可爱的,没有退,就这样开始喂养。

之前的金鱼因为晚上没有打氧死掉的。所以这次做足了功课。这条“马尾”取名久久,我们希望它能获得久一点。久久不仅漂亮,还很活泼,在水里游动的姿势很是好看。而且它似乎有灵性,看它或者喂食的时候,久久会凑过来,小嘴一张一合,好像在回应。

养了几天,我们开始寻思给久久找对象了。于是再买了一条身体有青花瓷一般花纹的小鱼,取名白莲花。斗鱼本是不能养在一起,这条母鱼更是母老虎。放进去就和久久打了起来。刚开始久久一直躲着,马尾被咬缺了,再后来马尾被咬的像布条一样。久久也是有脾气的,后面开始反击了。看样子他们不合适,我们把这两天分别放在不同的盒子里。隔着透明盒子,白莲花还在挑衅。喂食的时候发现其实白莲花的鱼嘴是有受伤的,即使这样,只要一见到其他鱼,就想打架。它在的盒子用东西拦着,挡住它视线,让它看不到其他盒子鱼。莲花碧池活该单身。

继续阅读“养鱼记”

我可不敢逃离北上广,小地方比大城市难混多了!

我认识的一对辞职卖房去大理开民宿的朋友,最近上了某知名媒体的头条,他们的美好生活方式被分发给了焦虑的北上广中青年们舔屏。

视频画面里随便都是剔透温暖的阳光、明净无尘的蓝天、棉花糖一样的云朵和波光粼粼的洱海。他们有一个漂亮的院子,精心种了玫瑰花墙和层次分明的花草,不认识的猫咪会随时随地跑来撒娇卖萌,推门进来跟夫妇俩喝酒吃饭闲话家常的,是有名有姓的画家、红到发紫的建筑师、各行各业的名人……总之,往来无白丁。

这一切几乎就是每个人最向往的那种生活:舒适惬意、没有压力、有格调有美景有人情味儿,而且事业一点没耽搁还原地起飞……无法更完美。

好几个共同认识、平时看上去营营役役、连出来喝一杯都提不起兴趣的中年人,不约而同地在不同场合提起这篇报道,羡慕之情溢于言表:“你说我们苦逼呵呵地非要留在北上广,到底图什么?”

他们图什么我不知道,但是每次遇到这种谈论我都微笑沉默,从不附和。

《卡萨布兰卡》里有句台词说:“世上有那么多的酒馆,她却偏偏走进了我的”。这句话改一改可以这么说:“世上有那么多的民宿,它却偏偏报道了我的”——这可不是缘分、巧合、随随便便。因为认识,所以我才知道两口子为这民宿付出了什么:所有辛苦经营、迎来送往、全面调度自身资源、周全打点上下关系,才成就了这番被传颂、被艳羡的美好生活。

而这过程中要求的任何一种能力,诸如社交、规划、整合……我都不具备或者不擅长,也因此,我心甘情愿留在北京,继续做着不太需要这些能力的工作。

继续阅读“我可不敢逃离北上广,小地方比大城市难混多了!”

Docker Desktop for Windows

自从使用Docker就变得一发不可收拾。和以前用虚拟机相比,它占资源少,启动快,方便管理。我主要用Docker来管理多个版本的软件共存、切换和升级,比如数据库,NextCloud,Wordpress。

开源的东西总是衷爱Linux,像Docker在Windows下就没那么方便。Windows的Linux子系统目前还不支付Docker,据说下个版本,WSL2会支付。所以我一直都是用VMware安装Linux,再安装Docker。

其实官方有提供在Windows环境下使用Docker的支持。一种是Docker Toolbox
工具,它是基于Oracle的VirtualBox虚拟机的,兼容性好,Windows各个版本都能用。还有一种是Docker Desktop for Windows,它是基于Hyper-V虚拟机。Hyper-V是微软的虚拟机,只在Windows专业版、企业版、工作站版中有。打开控制面板-程序-启用或关闭Windows功能,勾选Hyper-V,确定然后重启生效。

需要注意的是,Hyper-V和VMware、VirtualBox有冲突,开启后,VMware和VirtualBox包括Android虚拟机就不能使用CPU虚拟化了,性能会大打折扣。

从官网,docker.com下载Docker Desktop for Windows安装,安装完成后Docker会自动连接Hyper-V创建MobyLinux系统。Docker可能会提示需要用户登录,如果没有,可以去官网注册一个Docker账号。下载镜像是必须登录的。

继续阅读“Docker Desktop for Windows”

MySQL多实例启动

一台服务器安装MySQL,用于测试。同时会用于NextCloud和Wordpress的数据库。NextCloud和Wordpress要经常备份,而且以后可能会迁移。所以隔离不同情景的数据,用多实例启动。便于管理,和提高性能。

首先初始化要用到的数据库:

mysqld --initialize-insecure --datadir=/home/mysql/3307/data --user=mysql;
mysqld --initialize-insecure --datadir=/home/mysql/3308/data --user=mysql;
mysqld --initialize-insecure --datadir=/home/mysql/3309/data --user=mysql;

MySQL自带了mysqld_multi工具运行多个实例。以下是我的配置文件:

[mysqld_multi]
mysqld = /usr/bin/mysqld_safe
mysqladmin = /usr/bin/mysqladmin
user = root
#password = 

# nextcloud
[mysqld3307]
user		= mysql
pid-file	= /home/mysql/3307/mysqld.pid
socket		= /home/mysql/3307/mysqld.sock
port		= 3307
datadir		= /home/mysql/3307/data
lc-messages-dir	= /usr/share/mysql
skip-external-locking
bind-address		= 0.0.0.0
key_buffer_size		= 16M
max_allowed_packet	= 16M
thread_stack		= 192K
thread_cache_size       = 8
myisam-recover-options  = BACKUP
query_cache_limit	= 1M
query_cache_size        = 16M
expire_logs_days	= 10
max_binlog_size   = 100M
innodb_buffer_pool_size = 1G
innodb_io_capacity = 4000

# wordpress
[mysqld3308]
user		= mysql
pid-file	= /home/mysql/3308/mysqld.pid
socket		= /home/mysql/3308/mysqld.sock
port		= 3308
datadir		= /home/mysql/3308/data
lc-messages-dir	= /usr/share/mysql
skip-external-locking
bind-address		= 0.0.0.0
key_buffer_size		= 16M
max_allowed_packet	= 16M
thread_stack		= 192K
thread_cache_size       = 8
myisam-recover-options  = BACKUP
query_cache_limit	= 1M
query_cache_size        = 16M
expire_logs_days	= 10
max_binlog_size   = 100M
innodb_buffer_pool_size = 1G
innodb_io_capacity = 4000
innodb_io_capacity = 4000

[mysqld3309]
user		= mysql
pid-file	= /home/mysql/3309/mysqld.pid
socket		= /home/mysql/3309/mysqld.sock
port		= 3309
datadir		= /home/mysql/3309/data
lc-messages-dir	= /usr/share/mysql
skip-external-locking
bind-address		= 0.0.0.0
key_buffer_size		= 16M
max_allowed_packet	= 16M
thread_stack		= 192K
thread_cache_size       = 8
myisam-recover-options  = BACKUP
query_cache_limit	= 1M
query_cache_size        = 16M
expire_logs_days	= 10
max_binlog_size   = 100M
innodb_buffer_pool_size = 1G
innodb_io_capacity = 4000

配置多实例,每个实例命名为mysqld*,这里我三个实例配置分别对应[mysql3307],[mysql3308],[mysql3309]。

继续阅读“MySQL多实例启动”

Ubuntu Server初始化MySQL的坑

执行MySQL初始化:

mysqld --initialize --datadir=/home/mysql/3307/data --user=mysql

报错,提示不能创建目录:mysqld: Can’t create directory ‘/home/mysql/3307/data/’ (Errcode: 17 – File exists)

建立目录再执行初始化命令,提示没有权限:mysqld: Can’t create directory ‘/home/mysql/3307/data/’ (Errcode: 13 – Permission denied)

该目录已经属于mysql用户,且有读写执行的权限。设置成0777,依然报错。

相同的命令,曾在CentOS上,自己编译的MySQL用过,不应该是命令的问题。该机器是我的笔记本,安装的是Ubuntu Server 18.04,MySQL是用官方的apt源安装的。经过一番查找,发现是一个叫AppArmor的玩意搞鬼。

Ubuntu有个AppArmor,是一个Linux系统安全应用程序,类似于Selinux,AppArmor默认安全策略定义个别应用程序可以访问系统资源和各自的特权,如果不设置服务的执行程序,即使你改了属主属组并0777权限,也是对服务起不到作用。

继续阅读“Ubuntu Server初始化MySQL的坑”

Spring Boot集成Cache和Redis

构建基于Spring Boot 2.X应用,使用Cache,需要引入:

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

以前开发Spring用EhCache来做缓存。在做集群或分布式时,还是Redis比较好用。引入Spring Data Redis如下:

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

注意这里会有jedis依赖。

在applicatin.yml配置Redis和Cache:

spring:
  cache:
    redis:
      cache-names:
      cache-null-values: false
      key-prefix: spring:cache
      time-to-live: 0
      use-key-prefix: true
    type: # Cache type. By default, auto-detected according to the environment.
  redis:
    database: 5
    url: # Connection URL. Overrides host, port, and password. User is ignored. Example: redis://user:password@example.com:6379
    host: 127.0.0.1
    port: 6379
    password:
    timeout: 3000
    jedis:
      pool:
        max-active: 200
        max-idle: 10
        max-wait: -1
        min-idle: 0

更多配置属性可参考Spring Boot官方说明:

新建RedisConfig类,增加如下方法:

/**
 * 定义缓存数据 key 生成策略的bean
 * 包名+类名+方法名+所有参数
 * @return
 */
@Bean
public KeyGenerator wiselyKeyGenerator(){
	return new KeyGenerator() {
		@Override
		public Object generate(Object target, Method method, Object... params) {
			StringBuilder buff = new StringBuilder();
			buff.append(target.getClass().getName());
			buff.append(method.getName());
			for (Object obj : params) {
				buff.append(obj.toString());
			}
			return buff.toString();
		}
	};
}
继续阅读“Spring Boot集成Cache和Redis”