在EntityFrameworkCore项目下移除包Microsoft.EntityFrameworkCore.SqlServer 在EntityFrameworkCore项目下添加包Pomelo.EntityFrameworkCore.MySql v3.2.4 修改xxxDbContextConfigurer中的 删除EntityFraweorkCore下面的迁移文件夹 EntityFraweorkCore和WebHost的appsettings.json
|
1 2 3 |
"ConnectionStrings": { "Default": "server=127.0.0.1;database=abp;uid=root;pwd=123456;charset=utf8mb4;" }, |
添加数据迁移VS菜单:Tools -> NuGet Package Manager -> Package Manager Console运行以下命令:
|
1 |
Add-Migration DbName |
Update-Database Remove-Migration from:https://blog.csdn.net/qq_40353040/article/details/108770993
View DetailsSecureRandom在java各种组件中使用广泛,可以可靠的产生随机数。但在大量产生随机数的场景下,性能会较低。这时可以使用"-Djava.security.egd=file:/dev/./urandom"加快随机数产生过程。 以产生uuid的时候使用nextBytes产生随机数为入口,xSecureRandom的代码逻辑。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public static UUID randomUUID() { SecureRandom ng =Holder.numberGenerator; byte[] randomBytes = newbyte[16]; ng.nextBytes(randomBytes); randomBytes[6] &= 0x0f; /* clear version */ randomBytes[6] |=0x40; /* set to version 4 */ randomBytes[8] &= 0x3f; /* clear variant */ randomBytes[8] |=0x80; /* set to IETF variant */ return newUUID(randomBytes); } |
使用了SecureRandom.next*的方法。 在使用SecureRandom产生下一个随机数的时候调用nextLong或者nextBytes,最终会调用SecureRandom的nextBytes。
|
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 |
public long nextLong() { // it's okay that the bottom wordremains signed. return ((long)(next(32)) << 32)+ next(32); } final protected int next(int numBits) { int numBytes = (numBits+7)/8; byte b[] = new byte[numBytes]; int next = 0; nextBytes(b); for (int i = 0; i < numBytes; i++) next = (next << 8)+ (b[i] & 0xFF); return next >>> (numBytes*8 -numBits); } |
而nextBytes是一个同步的方法,在多线程使用时,可能会产生性能瓶颈。
|
1 2 3 4 5 |
synchronized public void nextBytes(byte[] bytes) { secureRandomSpi.engineNextBytes(bytes); } |
secureRandomSpi被初始化为sun.security.provider.SecureRandom secureRandomSpi是SecureRandom.NativePRNG的一个实例。 使用jvm参数-Djava.security.debug=all ,可以打印securityprovider列表,从中可以看出,SecureRandom.NativePRNG由sun.security.provider.NativePRNG提供服务。 Provider: Set SUN provider property[SecureRandom.NativePRNG/sun.security.provider.NativePRNG] 分析openjdk的源码,NativePRNG.engineNextBytes调用了NativePRNG.RandomIO.ensureBufferValid,而ensureBufferValid直接从urandom读取数据:
|
1 2 3 4 5 6 7 8 9 |
private void ensureBufferValid() throws IOException { ... readFully(urandomIn, urandomBuffer); ... } |
通过测试可以发现,hotspot需要使用配置项"-Djava.security.egd=file:/dev/./urandom"才能从urandom读取数据,这里openjdk做了优化,直接从urandom读取数据。 /dev/random在产生大量随机数的时候比/dev/urandom慢,所以,建议在大量使用随机数的时候,将随机数发生器指定为/dev/./urandom。 转自:https://blog.51cto.com/leo01/1795447 from:https://blog.csdn.net/wangooo/article/details/109139129
View Details一:最基本的Dockerfile构建Springboot项目 在pom同目录下新建Dockerfile
|
1 2 3 4 |
FROM openjdk:8-jdk-alpine VOLUME /tmp COPY target/*.jar app.jar ENTRYPOINT ["java","-jar","/app.jar"] |
将Springboot使用Maven打包,在终端中传参进去,进行构建Images。
|
1 2 3 |
docker build --build-arg=target/*.jar -t demo1/app . #构建完成后启动容器 docker run -p 8080:8080 demo1/app |
给Springboot启动时候传环境变量或者shell参数
|
1 2 3 4 5 |
FROM openjdk:8-jdk-alpine VOLUME /tmp ARG JAR_FILE COPY ${JAR_FILE} app.jar ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar ${0} ${@}"] |
指定JVM参数和shell参数
|
1 |
docker run -p 9000:9000 -e "JAVA_OPTS=-Ddebug -Xmx128m" demo1/app --server.port=9000 |
二:使用Idea可视化管理docker, 构建Springboot容器 这个在我另外一篇文章有讲到,都比较简单,有啥问题请留言。 三:使用Maven插件自动化构建Image https://github.com/spotify/dockerfile-maven ,能力强的可以直接去看README.md。 简单介绍一下这个插件做啥用的 通过pom配置docker构建Image过程,参数等 。 封装了自动化build,push,run等Maven命令 。 * 需要依赖Dockerfile,Dockerfile与pom.xml位于同一个目录下。 在pom.xml同目录下创建Dockerfile
|
1 2 3 4 |
FROM openjdk:8-jre ENTRYPOINT ["/usr/bin/java", "-jar", "/usr/share/myservice/app.jar"] ARG JAR_FILE ADD target/${JAR_FILE} /usr/share/myservice/app.jar |
在pom中添加
|
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 |
<plugin> <groupId>com.spotify</groupId> <artifactId>dockerfile-maven-plugin</artifactId> <version>1.4.13</version> <executions> <execution> <id>default</id> <goals> <goal>build</goal> <goal>push</goal> </goals> </execution> </executions> <configuration> <!--你需要配置的地方--> <!--指定仓库名/镜像名--> <repository>myrep/${project.artifactId}</repository> <!--指定tag --> <tag>${project.version}</tag> <buildArgs> <!--指定参数jar--> <JAR_FILE>${project.build.finalName}.jar</JAR_FILE> </buildArgs> </configuration> </plugin> |
最后在Idea Maven插件Plugins点击docker:build即可。或者输入命令
|
1 |
mvn com.spotify:dockerfile-maven-plugin:build |
四:使用Google的Maven插件进行容器管理(重头戏) Google开源项目Jib,对比上面那个插件Jib的Start数为7.8k,dockerfile-maven 为2.4k。 maven 插件
|
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 |
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>1.6.0</version> <configuration> <!--配置基本镜像--> <from> <image>openjdk:8-jdk-alpine</image> </from> <!--配置最终推送的地址,仓库名,镜像名--> <to> <image>registry.hub.docker.com/maoduntt/test</image> </to> </configuration> <!--绑定到maven lifecicle--> <executions> <execution> <phase>package</phase> <goals> <goal>build</goal> </goals> </execution> </executions> </plugin> |
配置maven docker hub账户和密码,在maven settings.xml中添加
|
1 2 3 4 5 |
<server> <id>registry.hub.docker.com</id> <username>你的dockerhub用户名</username> <password>你的dockerhub密码</password> </server> |
在idea maven插件中点击或者maven命令 mvn compile jib:buildTar 可以看到推送远程成功,Jib不需要写Dockerfile只需要你在插件中定义构建类型,所以使用时请多参考github的文档。最后现在也有这种开源的容器云平台,可以去了解下。 from:https://zhuanlan.zhihu.com/p/89161347
View Details环境: 1、代码编写工具:IDEA 2、打包:maven 3、docker 4、linux 7、JDK1.8 8、Xshell 9、Xftp 第一步:使用idea创建简单的springboot项目 第二步:设置项目生成jar包(两种方式) 1、修改pom文件
|
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 52 53 |
<?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.example</groupId> <artifactId>ordinary</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>ordinary</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <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</artifactId> </dependency> <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> </plugins> </build> </project> |
2、或者在生成项目的时候 可以选择jar和war 第三步:使用maven 生成包 (使用idea不用命令 直接界面操作就可以(如果Maven设置没问题 直接就可以生成 包 log会提示生成后的文件目录)) 第四步:docker概念 1、docker:最早是dotCloud公司出品的一套容器管理工具,但后来Docker慢慢火起来了,连公司名字都从dotCloud改成Docker。 2、dockerfile:它是Docker镜像的描述文件,可以理解成火箭发射的A、B、C、D……的步骤。 3、docker镜像:通过Dockerfile做出来的,包含操作系统基础文件和软件运行环境,它使用分层的存储方式。 4、docker容器:是运行起来的镜像,简单理解,Docker镜像相当于程序,容器相当于进程。 第四步:dockerfile指令 Dockerfile由多条指令组成,每条指令在编译镜像时执行相应的程序完成某些功能,由指令+参数组成,以逗号分隔,#作为注释起始符,虽说指令不区分大小写,但是一般指令使用大些,参数使用小写 第五步:dockerfile文件例子(我只是简单将springboot项目生成docker镜像没有什么多余配置) TODO:有一点需要注意的地方就是dockerfile文件没有任何后缀
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Pull base image FROM java:8 MAINTAINER yihj "yihj@yinghaikeji.com" VOLUME /tmp # 添加 ADD ordinary.jar app.jar RUN bash -c 'touch /app.jar' # Define default command. ENTRYPOINT ["java","-Dspring.profiles.active=online","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] #设置时区 RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone |
第六步:将dockerfile文件和生成好的jar 使用ftp工具上传到linux服务器 随便找个文件夹 放进去 jar和dockerfile在同级目录下 第七步:使用 docker build -t ordinary:v1.0 . TODO: 1、 最后面的这个 . 代表在当前目录下面寻找 dockerfile 文件 2、ordinary 镜像名字 3、v1.0版本 第八步:查看镜像及启动 1、使用docker images 来查看生成的镜像 2、使用docker create 来创建容器 docker run 来创建并且运行容器 3、也可以使用docker logs 容器名 --tail 100 -f 来查看项目启动日志 看项目是否启动 3、如果上面步骤一切正常 可以直接调用IP加端口来访问项目 通过Docker run命令定义Spring Profile 可以将spring profile作为环境变量传递给docker run命令,使用 -e 标记。 例如 -e “SPRING_PROFILES_ACTIVE=dev”会将dev profile传递给Docker容器 docker run -d -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" […]
View Details1.创建springboot项目 创建springboot项目
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.eangulee.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class HelloController { @RequestMapping("/") @ResponseBody public String hello() { return "Hello, SpringBoot With Docker"; } } |
2.打包springboot项目为jar包 3. 编写Dockerfile文件
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Docker image for springboot file run # VERSION 0.0.1 # Author: eangulee # 基础镜像使用java FROM java:8 # 作者 MAINTAINER eangulee <eangulee@gmail.com> # VOLUME 指定了临时文件目录为/tmp。 # 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp VOLUME /tmp # 将jar包添加到容器中并更名为app.jar ADD demo-0.0.1-SNAPSHOT.jar app.jar # 运行jar包 RUN bash -c 'touch /app.jar' ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] |
解释下这个配置文件: VOLUME 指定了临时文件目录为/tmp。其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp。该步骤是可选的,如果涉及到文件系统的应用就很有必要了。/tmp目录用来持久化到 Docker 数据文件夹,因为 Spring Boot 使用的内嵌 Tomcat 容器默认使用/tmp作为工作目录 项目的 jar 文件作为 “app.jar” 添加到容器的 ENTRYPOINT 执行项目 app.jar。为了缩短 Tomcat 启动时间,添加一个系统属性指向 “/dev/./urandom” 作为 Entropy Source 如果是第一次打包,它会自动下载java 8的镜像作为基础镜像,以后再制作镜像的时候就不会再下载了。 4. 部署文件 在服务器新建一个docker文件夹,将maven打包好的jar包和Dockerfile文件复制到服务器的docker文件夹下 docker文件夹 5. 制作镜像 执行下面命令, 看好,最后面有个"."点!
|
1 |
docker build -t springbootdemo4docker . |
-t 参数是指定此镜像的tag名 制作完成后通过docker images命令查看我们制作的镜像 6.启动容器
|
1 2 3 |
[root@localhost docker]# docker run -d -p 8080:8085 springbootdemo4docker -d参数是让容器后台运行 -p 是做端口映射,此时将服务器中的8080端口映射到容器中的8085(项目中端口配置的是8085)端口 |
7. 访问网站 直接浏览器访问: http://你的服务器ip地址:8080/ 好了,下一步就是学习springboot+mysql+redis如何在docker上如何部署了。 作者:雄关漫道从头越 链接:https://www.jianshu.com/p/397929dbc27d 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
View Details|
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
using System; using System.Collections.Generic; using System.Configuration; using MySql.Data.MySqlClient; using System.Data; namespace Utils { /// <summary> /// MySQL数据库工具类 /// </summary> public abstract class MySQLUtil { /// <summary> /// 数据库连接字符串 /// </summary> public static readonly string ConnStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; /// <summary> /// 执行语句并返回影响的行数 /// </summary> /// <param name="connStr">数据库连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>影响的行数</returns> public static int ExecuteNonQuery(string connStr, CommandType cmdType, string cmdText, params MySqlParameter[] parameters) { using (var conn = new MySqlConnection(connStr)) { return ExecuteNonQuery(conn, cmdType, cmdText, parameters); } } /// <summary> /// 执行语句并返回影响的行数 /// </summary> /// <param name="conn">数据库连接</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>影响的行数</returns> public static int ExecuteNonQuery(MySqlConnection conn, CommandType cmdType, string cmdText, params MySqlParameter[] parameters) { using (var cmd = new MySqlCommand()) { PrepareCommand(cmd, conn, null, cmdType, cmdText, parameters); var val = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); return val; } } /// <summary> /// 执行语句并返回影响的行数 /// </summary> /// <param name="trans">事务</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>影响的行数</returns> public static int ExecuteNonQuery(MySqlTransaction trans, CommandType cmdType, string cmdText, params MySqlParameter[] parameters) { using (var cmd = new MySqlCommand()) { PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, parameters); var val = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); return val; } } /// <summary> /// 执行语句并返回DataReader对象 /// </summary> /// <param name="connStr">数据库连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>执行语句并返回DataReader对象</returns> /// <remarks>P.S:DataReader使用后要手动释放</remarks> public static MySqlDataReader ExecuteReader(string connStr, CommandType cmdType, string cmdText, params MySqlParameter[] parameters) { var cmd = new MySqlCommand(); var conn = new MySqlConnection(connStr); try { PrepareCommand(cmd, conn, null, cmdType, cmdText, parameters); var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); cmd.Parameters.Clear(); return dr; } catch { conn.Close(); throw; } } /// <summary> /// 执行语句并返回DataSet对象 /// </summary> /// <param name="cmdText"></param> /// <param name="parameters"></param> /// <returns></returns> public static DataSet ExecuteDataSet(string cmdText, params MySqlParameter[] parameters) { return ExecuteDataSet(ConnStr, CommandType.Text, cmdText, parameters); } /// <summary> /// 执行语句并返回DataSet对象 /// </summary> /// <param name="connStr">数据库连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>执行语句并返回DataSet对象</returns> /// <returns></returns> public static DataSet ExecuteDataSet(string connStr, CommandType cmdType, string cmdText, params MySqlParameter[] parameters) { using (var conn = new MySqlConnection(connStr)) { return ExecuteDataSet(conn, cmdType, cmdText, parameters); } } /// <summary> /// 执行语句并返回DataSet对象 /// </summary> /// <param name="connStr">数据库连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>执行语句并返回DataSet对象</returns> /// <returns></returns> public static DataSet ExecuteDataSet(MySqlConnection conn, CommandType cmdType, string cmdText, params MySqlParameter[] parameters) { using (var cmd = new MySqlCommand()) { PrepareCommand(cmd, conn, null, cmdType, cmdText, parameters); using (var da = new MySqlDataAdapter(cmd)) { var ds = new DataSet(); try { da.Fill(ds, "ds"); cmd.Parameters.Clear(); } catch (MySqlException ex) { throw new Exception(ex.Message); } return ds; } } } /// <summary> /// 执行语句并返回一个对象 /// </summary> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>返回一个object对象,对象中只包含一列。</returns> public static object ExecuteScalar(string cmdText, params MySqlParameter[] parameters) { return ExecuteScalar(ConnStr, CommandType.Text, cmdText, parameters); } /// <summary> /// 执行语句并返回一个对象 /// </summary> /// <param name="connStr">数据库连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>返回一个object对象,对象中只包含一列。</returns> public static object ExecuteScalar(string connStr, CommandType cmdType, string cmdText, params MySqlParameter[] parameters) { using (var conn = new MySqlConnection(connStr)) { return ExecuteScalar(conn, cmdType, cmdText, parameters); } } /// <summary> /// 执行语句并返回一个对象 /// </summary> /// <param name="conn">数据库连接</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="parameters">参数集</param> /// <returns>返回一个object对象,对象中只包含一列。</returns> public static object ExecuteScalar(MySqlConnection conn, CommandType cmdType, string cmdText, params MySqlParameter[] parameters) { using (var cmd = new MySqlCommand()) { PrepareCommand(cmd, conn, null, cmdType, cmdText, parameters); var val = cmd.ExecuteScalar(); cmd.Parameters.Clear(); return val; } } /// <summary> /// 为执行准备命令对象 /// </summary> /// <param name="cmd">command 对象</param> /// <param name="conn">连接对象</param> /// <param name="trans">事务对象</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="cmdParms">参数集</param> private static void PrepareCommand(MySqlCommand cmd, MySqlConnection conn, MySqlTransaction trans, CommandType cmdType, string cmdText, IEnumerable<MySqlParameter> parameters) { if (conn.State != ConnectionState.Open) conn.Open(); cmd.Connection = conn; cmd.CommandText = cmdText; if (trans != null) cmd.Transaction = trans; cmd.CommandType = cmdType; if (parameters == null) return; foreach (var parm in parameters) cmd.Parameters.Add(parm); } } } |
View Details
这种问题是因为你提交的Form中有HTML字符串,例如你在TextBox中输入了html标签,或者在页面中使用了HtmlEditor组件等,解决办法是禁用validateRequest。 如果你是.net 4.0或更高版本,一定要看方法3。 此方法在asp.net webForm和MVC中均适用 方法1: 在.aspx文件头中加入这句:
|
1 |
<%@ Page validateRequest="false" %> |
方法2: 修改web.config文件:
|
1 2 3 4 5 |
<configuration> <system.web> <pages validateRequest="false" /> </system.web> </configuration> |
因为validateRequest默认值为true。只要设为false即可。 方法3: web.config里面加上
|
1 2 3 |
<system.web> <httpRuntime requestValidationMode="2.0" /> </system.web> |
因为4.0的验证在HTTP的BeginRequest前启用,因此,请求的验证适用于所有ASP.NET资源,aspx页面,ashx页面,Web服务和一些HTTP处理程序等. from:https://www.cnblogs.com/youring2/p/3559781.html
View Details🥝 NuGet引用log4net 🥝 Configs文件夹下创建log4net.config
|
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <log4net> <appender name="InfoRollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="Logs\\" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyyMM\\"info_"yyyy-MM-dd".log"" /> <staticLogFileName value="false" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="***************************************************************************************************************************************************%n[%d] [%p] [%F Line:%L] %m%n" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="INFO" /> <param name="LevelMax" value="INFO" /> </filter> </appender> <appender name="DebugRollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="Logs\\" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyyMM\\"debug_"yyyy-MM-dd".log"" /> <staticLogFileName value="false" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="***************************************************************************************************************************************************%n[%d] [%p] [%F Line:%L] %m%n" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="DEBUG" /> <param name="LevelMax" value="DEBUG" /> </filter> </appender> <appender name="WarnRollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="Logs\\" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyyMM\\"warn_"yyyy-MM-dd".log"" /> <staticLogFileName value="false" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="***************************************************************************************************************************************************%n[%d] [%p] [%F Line:%L] %m%n" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="WARN" /> <param name="LevelMax" value="WARN" /> </filter> </appender> <appender name="ErrorRollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="Logs\\" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyyMM\\"error_"yyyy-MM-dd".log"" /> <staticLogFileName value="false" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="***************************************************************************************************************************************************%n[%d] [%p] [%F Line:%L] %m%n" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="Error" /> <param name="LevelMax" value="FATAL" /> </filter> </appender> <root> <appender-ref ref="InfoRollingLogFileAppender" /> <appender-ref ref="DebugRollingLogFileAppender" /> <appender-ref ref="WarnRollingLogFileAppender" /> <appender-ref ref="ErrorRollingLogFileAppender" /> </root> </log4net> </configuration> |
🥝 AssemblyInfo.cs文件下添加
|
1 |
[assembly: log4net.Config.XmlConfigurator(ConfigFile = @"Configs\log4net.config", Watch = true)] |
🥝 类中引用
|
1 |
private ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
View Details
最近在写一些东西的时候,有一些数据是使用XML来保存的,而其中有一些数据是一段HTML文本,一开始觉得没什么问题,当把这些HTML放到XML的一个结点的时候,才发现数据已经变样了。 原来在XML中有5个预定义的实体引用: < < 小于 > > 大于 & & 和号 ' ' 省略号 " " 引号 参考:http://www.w3school.com.cn/xml/xml_cdata.asp HTML和XML差不多,是由一些预定义的标签组成的,所以包含了大量的"<"、">"符号。 所以有两个方法可以将HTML插入到XML中: 1、将HTML进行一次转换,将所有的"<"、">"等预定义符号转换成相应的实体引用。 2、将HTML包在CDATA中。 很明显,第一种方法比较烦琐,序列化数据的时候和把序列化的时候都需要进行转换。 第二种方法则很简单了。 写了一个方法:
|
1 2 3 4 5 6 7 |
public class XMLUtil { public static function CDATA(data:String):XML { return new XML( " <![CDATA[ " + data + " ]]\> " ); } } |
可以这样使用:
|
1 |
var node:XML = < node > {XMLUtil.CDATA( " 字符串 " )} </ node > ; |
参考: http://cookbooks.adobe.com/post_Create_CDATA_tags_between_XML_nodes_using_AS-6142.html 转载于:https://www.cnblogs.com/yili16438/archive/2011/04/13/2015369.html from:https://blog.csdn.net/weixin_30556161/article/details/97479499
View Details缘由 我们在使用spring boot开发的服务中,一般会选择打包成单体的fatjar来发布服务,这在传统的部署方式下是非常方便的,但是当我们选择使用docker这种容器化的方式来部署应用的时候,却有一点点的不便之处,因为这个单体的jar一般都比较大,每次镜像push到仓库和从仓库拉取都需要比较长的时间。 原因是什么了? docker的一大特色就是镜像的存储是分层的,参考下面这张官图 我们在Dockerfile中的每一个指令会对应到镜像的每一层,docker在更新镜像时,只会推送变更过的层,当它计算出来这一层的摘要和之前的版本一致时,会复用上一次打包镜像时的缓存,会极大的提高打包镜像以及镜像push/pull操作的速度。 那么问题来了,当我们springboot打包出来的单体jar的时候,每次编译这个jar都会发生变化,对应的存储层也会发生变化,push和pull操作时都需要重新推送,而且这个jar一般都不小,一个典型的应用会在100M左右,对应用部署和发布的速度会有比较大的影响。 稍作思考,很容易就能发现这个肥大的jar文件里面,大部分其实都是固定不变的各种依赖库,我们真正每次编译会变化的业务代码部分其实很小很小,可能也就只有几百KB,只要能将这两部分分离,变成docker镜像中的两层,一定能极大的提升镜像发布的速度 牛刀小试 首先拿来动手尝试的是一个springboot admin的项目,项目的结构是这样的: 使用最常见的打包方式:
|
1 2 3 4 |
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> |
会生成一个32M的jar文件,优化之前的Dockerfile非常简单:
|
1 2 3 4 5 6 7 8 |
FROM openjdk:11.0.5-stretch as builder RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone VOLUME /tmp COPY target/*.jar ./app.jar CMD ["/bin/bash", "-c", "java -jar -server app.jar"] EXPOSE 8080 |
可以看到这种方式在构建v2版本的镜像时,会重新copy整个完整的jar 如果要拆开这个单体的jar,有两种方式,一是修改mvn打包的配置,将lib包放在独立的文件夹下,在这里我们考虑到项目众多,尽量减少修改,选择了在Docker打包镜像时,解压打包出来的jar包,将其中的内容分开来copy,修改后的Dockerfile如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#采用docker的分阶段构建方式,第一阶段负责解压jar包 FROM openjdk:11.0.5-stretch as builder RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone VOLUME /tmp WORKDIR /target ADD target/*.jar app.jar RUN jar xf app.jar #这里分别copy解压后的内容 FROM openjdk:11.0.5-stretch VOLUME /tmp WORKDIR /app COPY --from=builder target/BOOT-INF/lib ./lib COPY --from=builder target/org/ ./org COPY --from=builder target/META-INF/ ./META-INF COPY --from=builder target/BOOT-INF/classes ./classes CMD ["/bin/bash", "-c", "java -cp .:./classes/:./lib/* -server org.springframework.boot.loader.JarLauncher"] EXPOSE 8080 |
看看修改后的效果: 在copy lib目录时,是直接using cache的。来看看push的时候效果对比 首先是优化前的push: 可以看到在push v2的时候还是会push一个33MB的层,虽然其实我们一行代码没有修改。 然后是优化后的: 可以看到这一次仅仅只推送了一个13KB的层,推送的速度快了非常多,同理也可以想象的到,我们在拉取镜像更新版本时速度会快很多。 路遇荆棘 在针对springboot-admin这个最简单的项目的优化取得很好的效果之后,就开始准备照搬到其他的项目中,没想到同样的方式怎么折腾都无效,分离之后的lib目录依然会每次需要全量重新push。出问题的项目结构大概是这样的: 一个常见的多模块mvn项目,有common,domain,rest-client,rest-server 这4个子模块,其中rest-server会依赖common和domain这两个子模块,打包出来的jar是在rest-server这个模块中。 究竟是什么鬼了? 终得正果 苦苦思索一番之后,lib目录既然不能复用上一次的cache,那一定是因为里面的内容有变化,遂将jar包解压,进到lib目录,真凶果然在此: 项目自身的3个子模块在每次编译的时候也会做为jar包放到lib目录下,这3个jar包每次编译都会有变化,所以导致这一层的cache失效。 找到问题之后,解决的思路就很简单了,将这种jar单独copy到一个目录下即可,修改后的Dockerfile如下:
|
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 |
FROM openjdk:11.0.5-stretch as builder RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone VOLUME /tmp WORKDIR /target ADD target/*.jar app.jar RUN jar xf app.jar #创建一个snapshot目录,把snapshot的jar复制过去 RUN mkdir BOOT-INF/snapshot RUN mv BOOT-INF/lib/*SNAPSHOT.jar BOOT-INF/snapshot/ FROM openjdk:11.0.5-stretch VOLUME /tmp WORKDIR /app COPY --from=builder target/BOOT-INF/lib ./lib COPY --from=builder target/org/ ./org COPY --from=builder target/META-INF/ ./META-INF #单独复制snapshot这一层 COPY --from=builder target/BOOT-INF/snapshot ./snapshot COPY --from=builder target/BOOT-INF/classes ./classes CMD ["/bin/bash", "-c", "java -cp .:./classes/:./lib/*:./snapshot/* -server org.springframework.boot.loader.JarLauncher"] EXPOSE 8089 |
这样修改之后效果就和上面单模块的项目一样了,至此,基本完成了springboot项目的docker镜像优化,在jenkins的流水线上可以将原来镜像push的时间从1分钟以上优化到10s左右 未来之路 在整个优化的过程中,发现springboot2.3 M1版本已经有针对性的优化方案,增加了LAYERED_JAR的打包格式,未来可期。 具体可参考下文: www.jdon.com/53738 注: 本文中举例的两个项目案例,可在github上找到:github.com/yishh/sprin… 作者:thor_lee 链接:https://juejin.cn/post/6844904119338008583 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
View Details