文档章节

JeeSite 4.0 简化MyBatis持久层开发

ThinkGem
 ThinkGem
发布于 2017/08/06 19:18
字数 3008
阅读 15681
收藏 11
点赞 20
评论 66

引言

在做这一方面研究的时候,本人参考了很多资料和框架,如MyBatis-Mapper、MyBatis-Plus等等,这些都做的很不错,本来想集成一个,尝试了下还是有多处地方不顺手,不易扩展,不能解决我的本意,既能使用方便又不能失灵活,所以决定自己试着完成一套Dao层架构,精简开发。

在此之前我先考虑API的写法,通俗易懂,大众思维。持久层实体类采用 @Table注解配置,自动生成增删改通用SQL,不需要在mapper.xml里写重复又费时的SQL,遇见复杂的情况下支持扩展。而报表统计分析的情况下又能支持mybatis原生写法,在写sql的时候,又能调用之前实体配置的一些参数。从而减少开发和后期维护成本。

众多的持久层框架@Column注解定义都是分布到get或属性上,或者干脆直接使用属性作为字段名,这在JeeSite是不推荐的,JeeSite的实体不仅仅是物理实体,它是与Model实体结合的一个产物,视乎记得JFinal作者也说过这一点,也是推荐的一个做法。总合考虑,将@Column所有定义到类头,而不是分布到各个属性或方法上,主要是有以下三点原因:

  1. 可一览熟知该实体类对应的物理表结构是什么样,引领开发者思维从物理表结构到对象的映射转换,都是基于物理表结构的,@Column中的name指定物理字段名,而不是指定类上的属性名,也是这个原因;
  2. 自动化生成的SQL和查询条件,是有序的,可方便核查定义,优化查询;
  3. 方便@JoinTable关联表和其它扩展信息的设置,如果分布到类的属性上就需要来回滚动屏幕查找,不利于管理字段列。

下面举例说明,最后附上API:

以定义员工实体举例,配置如下:(注意代码上的注释)

@Table(name="${_prefix}sys_employee", alias="a", columns={
		@Column(includeEntity=BaseEntity.class),        // 支持Include
		@Column(includeEntity=DataEntity.class),        // 支持Include,如:自动导入status、create_by、create_date等字段
		@Column(name="emp_code", label="员工编码", isPK=true),  // 支持设置主键PK字段,调用get方法时自动加入主键唯一条件
		@Column(name="emp_name", label="名称", queryType=QueryType.LIKE),  // 支持设置查询字段类型,如LIKE自动在查询值前后加 % 符号。
		@Column(name="emp_name_en", label="英文名", queryType=QueryType.LIKE),
		@Column(name="emp_no", label="工号"),   // 字段名到Java属性名的转换,采用驼峰命名法规则自动进行转换
		// 驼峰命名法转换不了的,支持设置特殊对象属性,如mapper.xml的sql中 a.office_code AS "office.officeCode" 的写法
		@Column(name="office_code", attrName="office.officeCode", label="机构编码"),  
		@Column(name="office_name", attrName="office.officeName", label="机构名称", queryType=QueryType.LIKE),
		@Column(name="company_code", attrName="company.companyCode", label="公司编码"),
		@Column(name="company_name", attrName="company.companyName", label="公司名称", queryType=QueryType.LIKE),
		@Column(name="sex", label="性别"),
		@Column(name="birthday", label="生日"),
		@Column(name="photo", label="员工照片", isQuery=false), // 支持设置非查询字段,添加查询条件时忽略该字段
		@Column(name="email", label="电子邮件"),
		@Column(name="mobile", label="手机号码"),
		@Column(name="phone", label="办公电话"),
		@Column(name="fax", label="传真号码"),
		@Column(name="qq", label="QQ号"),
		@Column(name="weixin", label="微信号"),
		@Column(name="stations", label="岗位"),
	},
	// 支持联合查询,如左右连接查询,支持设置查询自定义关联表的返回字段列
	joinTable={
		@JoinTable(type=Type.LEFT_JOIN, entity=Office.class, alias="o", 
			on="o.office_code = a.office_name",
			columns={@Column(includeEntity=Office.class)}),
		@JoinTable(type=Type.LEFT_JOIN, entity=Company.class, alias="c", 
			on="c.company_code = a.company_name",
			columns={@Column(includeEntity=Company.class)}),
	},
	// 支持扩展Column、Form、Where等,主要用于该注解实现不了的复杂情况,扩展SQL写法,这里设置的是sqlMap的key
	extWhereKeys="dsfOffice, dsfCompany"
	// 自动设置默认排序
	orderBy="a.update_date DESC"
)
public class Employee extends DataEntity<Employee> {
	private static final long serialVersionUID = 1L;
	private String empCode;		// 员工编码
	private String empName;		// 名称
	private String empNameEn;	// 英文名
	private String empNo;		// 工号
	private Office office;	    // 机构编码
	private Company company;	// 公司编码
	private String sex;			// 性别
	private Date birthday;		// 生日
	private String photo;		// 员工照片
	private String email;		// 电子邮件
	private String mobile;		// 手机号码
	private String phone;		// 办公电话
	private String fax;			// 传真号码
	private String qq;			// QQ号
	private String weixin;		// 微信号
	private String stations;	// 岗位
	
	/// 省略  get  set 方法
	
}

请仔细看上面的代码和注释,其以上之外,还支持是否为插入字段,是否为更新字段等等。

再举一个例子,扩展上面介绍的Employee表,与用户表联合查询单独定义实体,用户员工实体:

@Table(name="${_prefix}sys_user", alias="a", columns={
		@Column(includeEntity=User.class),
	}, joinTable={
		@JoinTable(type=Type.JOIN, entity=Employee.class, alias="e",
			on="e.emp_code = a.ref_code AND a.user_type=#{USER_TYPE_EMPLOYEE}",
			columns={@Column(includeEntity=Employee.class)}),
		@JoinTable(type=Type.LEFT_JOIN, entity=Office.class, alias="o", 
			on="o.office_code = a.office_name", attrName="employee.office",
			columns={@Column(includeEntity=Office.class)}),
		@JoinTable(type=Type.LEFT_JOIN, entity=Company.class, alias="c", 
			on="c.company_code = a.company_name", attrName="employee.company",
			columns={@Column(includeEntity=Company.class)}),
	}, extWhereKeys="dsfOffice, dsfCompany", orderBy="a.update_date DESC"
)
public class EmpUser extends User {
	private static final long serialVersionUID = 1L;
	public EmpUser() {
		this(null);
	}
	public EmpUser(String id){
		super(id);
	}
	@Valid
	public Employee getEmployee(){
		Employee employee = (Employee)super.getRefObj();
		if (employee == null){
			employee = new Employee();
		}
		return employee;
	}
	public void setEmployee(Employee employee){
		super.setRefObj(employee);
	}
}

注解配置完成了,下面看看如何使用

如何使用

贴了这么多配置代码,下面介绍下用法。

你的Dao只需要继承CrudDao即可享受便捷体验,是不是特Easy,如下:

/**
 * 员工管理DAO接口
 * @author ThinkGem
 */
@MyBatisDao(entity = Employee.class)
public interface EmployeeDao extends CrudDao<Employee> {

}

EmployeeDao继承CrudDao后,里面的方法你都可以调用,如下方法:

/**
 * DAO实现增删改接口
 * @author ThinkGem
 */
public interface CrudDao<T> extends QueryDao<T> {

	/**
	 * 插入数据
	 */
	public int insert(T entity);
	
	/**
	 * 批量插入数据
	 */
	public int insertBatch(List<T> entityList);

	/**
	 * 更新数据  By PK
	 */
	public int update(T entity);
	
	/**
	 * 更新数据  By Entity
	 */
	public int updateByEntity(T entity, T whereEntity);
	
	/**
	 * 更新状态数据  By PK
	 */
	public int updateStatus(T entity);
	
	/**
	 * 更新状态数据  By Entity
	 */
	public int updateStatusByEntity(T entity, T whereEntity);
	
	/**
	 * 删除数据  By PK(如果有status字段,则为逻辑删除,更新status字段为1,否则物理删除)
	 */
	public int delete(T whereEntity);
	
	/**
	 * 删除数据  By Entity(如果有status字段,则为逻辑删除,更新status字段为1,否则物理删除)
	 */
	public int deleteByEntity(T whereEntity);

	/**
	 * 获取单条数据
	 * @param entity
	 * @return entity
	 */
	public T get(T entity);
	
	/**
	 * 获取单条数据
	 * @param entity
	 * @return entity
	 */
	public T getByEntity(T entity);
	
	/**
	 * 查询数据列表,如果需要分页,请设置分页对象,如:entity.setPage(new Page<T>(pageNo, pageSize));
	 * @param entity
	 * @return
	 */
	public List<T> findList(T entity);
	
	/**
	 * 查询数据总数
	 * @param entity
	 * @return
	 */
	public long findCount(T entity);
	
}

调用举例:

// 查询一条,更新
Employee employee = new Employee();
employee.setEmpCode('E001');
employee = employeeDao.get(employee);
employee.setMobile('18666666666');
employeeDao.update(employee);

// 列表查询、统计
Employee employee = new Employee();
employee.setEmpName('小王');
employee.setPage(new Page(1, 20)); // 分页查询
List<Employee> list = employeeDao.findList(employee);
Long count = employeeDao.findCount(employee);

// 批量插入
employeeDao.insertBatch(list);

是不是有种事半功倍的感觉,小小的配置,可以实现几乎可以完成原来需要写代码的80%时间。

也许你会觉着配置复杂,难以理解,只要你用上了相信你就会爱不释手。

还有一个惊喜,这些配置也可以通过代码生成工具快速生成,喜欢不喜欢。

嗯!基本增删改查,批量操作,按实体属性查询,按实体属性更新,以及统计都有了 ↓↓↓ 可是 ↓↓↓

可是

这么多还是还不够,比如,我们想实现,日期范围查询怎么办?某个实体属性,实现双重查询(如那么既能eq又能like)怎么办?想实现or、is null,括号查询怎么办?这些都么关系,已经替你考虑了,如下:


////////// 日期范围查询,gte,lte ////////////////

public Date getCreateDate_gte(){
	return sqlMap.getWhere().getValue("create_date", QueryType.GTE);
}

public void setCreateDate_gte(Date createDate){
	createDate = DateUtils.getOfDayFirst(createDate); // 将日期的时间改为0点0分0秒
	sqlMap.getWhere().and("create_date", QueryType.GTE, createDate);
}

public Date getCreateDate_lte(){
	return sqlMap.getWhere().getValue("create_date", QueryType.LTE);
}

public void setCreateDate_lte(Date createDate){
	createDate = DateUtils.getOfDayLast(createDate); // 将日期的时间改为23点59分59秒
	sqlMap.getWhere().and("create_date", QueryType.LTE, createDate);
}

////////// 双重字段查询,支持eq,支持like ////////////////

public String getTableName() {
	return StringUtils.lowerCase(tableName);
}

public void setTableName(String tableName) {
	this.tableName = tableName;
}

public String getTableName_like() {
	return sqlMap.getWhere().getValue("table_name", QueryType.LIKE);
}

public void setTableName_like(String tableName) {
	sqlMap.getWhere().and("table_name", QueryType.LIKE, tableName);
}

////////// 实现 or、is null,括号 ////////////////

public String getParentTableName_isNull() {
	return this.getParentTableName();
}

public void setParentTableName_isNull(String parentTableName) {
	if (StringUtils.isBlank(parentTableName)){
		sqlMap.getWhere().andBracket("parent_table_name", QueryType.IS_NULL, null, 2)
			.or("parent_table_name", QueryType.EQ_FORCE, "", 3).endBracket();
		this.setParentTableName(null);
	}else{
		this.setParentTableName(parentTableName);
	}
}
	

还有一种情况,如所有的配置都配置好了,我只需要在sql返回值里加一个简单的统计数,多返回一列,你可以这样写:

// 实体类定义
@Table(name="${_prefix}gen_table", alias="a", columns={
    	// @Column 。。。此处省略 。。。
    },
    // 扩展Column里指定一个Key名字,类里并定义一个需要返回的属性和get set
    extColumnKeys="extColumn"
)
public class GenTable extends DataEntity<GenTable> {
	private Long childNum;				// 子表个数
	public Long getChildNum() {
		return childNum;
	}
	public void setChildNum(Long childNum) {
		this.childNum = childNum;
	}
}

// Service 里,通过sqlMap设置你刚定义的Key即可,如下
public Page<GenTable> findPage(Page<GenTable> page, GenTable genTable) {
	// 添加扩展列,查询子表个数
	String extColumn = "(SELECT count(1) FROM "+MapperHelper.getTableName(genTable)
		+" WHERE parent_table_name=a.table_name) AS \"childNum\"";
	genTable.getSqlMap().add("extColumn", extColumn);
	return super.findPage(page, genTable);
}

如果以上仍得不到你的满足,怎么办,那你可以写Mapper.xml了,比如EmployeeDao.xml一些通用的字段、条件,你就不需要在xml再写一遍了,你只需要补充SQL即可(相同id,如id="findList"则会自动覆盖默认设置):

<select id="findList" resultType="Employee">
	SELECT ${sqlMap.column.toSql('a')}
	FROM ${_prefix}sys_employee a
	<where>
		${sqlMap.where.toSql('a')}
	</where>
	ORDER BY ${sqlMap.order.toSql('a')}
</select>

这样的Dao,你满意吗?编码原来如此简单,提高了效率,又不损失灵活,是不是很有趣呢。

附:API

@Table

/**
 * 指定实体的物理表属性 
 * @author ThinkGem
 */
public @interface Table {

	/**
	 * 物理表名
	 */
	String name() default "";
	
	/**
	 * 当前表别名
	 */
	String alias() default "a";
	
	/**
	 * 表列定义
	 */
	Column[] columns();
	
	/**
	 * 查询,关联表
	 */
	JoinTable[] joinTable() default {};
	
	/**
	 * 指定排序
	 */
	String orderBy() default "";
	
	/**
	 * 表说明
	 */
	String comment() default "";
	
	/**
	 * 扩展ColumnSQL,在这里指定sqlMap的key。<br>
	 * 例如:\@Table(extColumnKeys="dataScopeColumn");<br>
	 * Service里设置:sqlMap.put("extColumn", "column_name AS \"columnName\"");<br>
	 * 在执行查询的时候,该语句放到自动会加到Where最后并执行。<br>
	 * <b>注意:</b>如果设置,必须后台代码中设置,否则可能造成sql注入漏洞<br>
	 */
	String extColumnKeys() default "";
	
	/**
	 * 扩展FromSQL,在这里指定sqlMap的key。<br>
	 * 例如:\@Table(extFromKeys="dataScopeFrom");<br>
	 * Service里设置:sqlMap.put("dataScopeFrom", "JOIN table_name t on t.pk=a.pk");<br>
	 * 在执行查询的时候,该语句放到自动会加到Where最后并执行。<br>
	 * <b>注意:</b>如果设置,必须后台代码中设置,否则可能造成sql注入漏洞<br>
	 */
	String extFromKeys() default "";
	
	/**
	 * 扩展WhereSQL,在这里指定sqlMap的key。<br>
	 * 例如:\@Table(extWhereKeys="dataScopeWhere");<br>
	 * Service里设置:sqlMap.put("dataScopeWhere", "AND column_name='value'");<br>
	 * 在执行查询的时候,该语句放到自动会加到Where最后并执行。<br>
	 * <b>注意:</b>如果设置,必须后台代码中设置,否则可能造成sql注入漏洞<br>
	 */
	String extWhereKeys() default "";
	
}

@Column

/**
 * 定义物理表列属性(不继承父类注解)
 * @author ThinkGem
 */
public @interface Column {

	/**
	 * 字段名(例如:config_key)
	 */
	String name() default "";

	/**
	 * 属性名,若不指定,则根据name()字段名进行驼峰命名法转换(例如:config_key 转换为   configKey)
	 */
	String attrName() default "";

	/**
	 * 属性名,定义的类型
	 */
	Class<?> type() default Class.class;
	
	/**
	 * 标签名
	 */
	String label() default "";
	
	/**
	 * 字段备注
	 */
	String comment() default "";

	/**
	 * 是否主键(update、delete时的条件)
	 */
	boolean isPK() default false;
	
	/**
	 * 是否插入字段
	 */
	boolean isInsert() default true;
	
	/**
	 * 是否更新字段
	 */
	boolean isUpdate() default true;
	
	/**
	 * 是否是查询字段
	 */
	boolean isQuery() default true;
	
	/**
	 * 查询类型
	 */
	QueryType queryType() default QueryType.EQ;
	
	/**
	 * 包含嵌入一个实体
	 */
	Class<?> includeEntity() default Class.class;
}

@JoinTable

/**
 * 指定实体的物理表的关联表属性 
 * @author ThinkGem
 */
public @interface JoinTable {
	
	/**
	 * 连接类型
	 */
	Type type() default Type.JOIN;
	public enum Type{
		JOIN("JOIN"), // INNER JOIN
		LEFT_JOIN("LEFT JOIN"),
		RIGHT_JOIN("RIGHT JOIN");
		private final String value;
		Type(String value) { this.value = value; }
		public String value() { return this.value; }
	}
	
	/**
	 * 连接的表,指定实体Class
	 */
	Class<?> entity();
	
	/**
	 * 当前表别名
	 */
	String alias();
	
	/**
	 * 连接表条件
	 */
	String on();
	
	/**
	 * 对应主表中对应的属性名,若不指定,则根据entity()进行首字母小写得到属性名(例如:Config 转换为   config)
	 */
	String attrName() default "";
	
	/**
	 * 连接表,返回的列,若不指定,则读取entity()的所有列。
	 */
	Column[] columns() default {};
	
}

QueryType

/**
 * 查询类型
 * @author ThinkGem
 */
public enum QueryType{
	
	EQ("="),
	NE("!="),
	GT(">"),
	GTE(">="),
	LT("<"),
	LTE("<="),
	IN("IN"),
	NOT_IN("NOT IN"),
	LIKE("LIKE", "%", "%"),
	LEFT_LIKE("LIKE", "%", ""),
	RIGHT_LIKE("LIKE", "", "%"),
	IS_NULL("IS NULL"),
	IS_NOT_NULL("IS NOT NULL"),
	
	// 强制条件,不管值是不是空字符串都加载这个查询条件
	EQ_FORCE("=", true),
	NE_FORCE("!=", true),
	
	;
}

© 著作权归作者所有

共有 人打赏支持
ThinkGem

ThinkGem

粉丝 856
博文 135
码字总数 20086
作品 1
济南
架构师
加载中

评论(66)

命运之零
命运之零
这个status属性是必须的么,我怎么取消这个属性的查询
比如现在会限制status != 1之类的,╮(╯﹏╰)╭╮
m
mathcoder23
作为菜鸟,用过注解,但我觉得xml还是比较适合我。
jeesite在代码生成方面,无法持续生成,这让我感觉很麻烦。
我想做一个能够持续生成代码的功能,比如增加表一个字段,会修改相应的自动生成代码区域。
并且在生成代码的设计上,代码生成与自定义功能要划分清楚等等。最近在考虑写这些功能。
ThinkGem
ThinkGem

引用来自“E路无忧”的评论

请问如何使用框架提供的注解实现一对多或多对多的功能,是不是还是需要通过xml来配置?
可以配置多对一,使用 JoinTable 注解,多对多实现其实就是,多个多对一的关系。虽说可以实现,但不建议很复杂的配置,复杂语句可以通过简单的xml写sql实现。
E
E路无忧
请问如何使用框架提供的注解实现一对多或多对多的功能,是不是还是需要通过xml来配置?
ThinkGem
ThinkGem

引用来自“ylmotol7”的评论

baseentity里面,为什么一定要搞一个id呢?能否自定义或被覆盖?
只是一个属性,可以忽略,注解里可指定isPK=true自定义主键
y
ylmotol7
baseentity里面,为什么一定要搞一个id呢?能否自定义或被覆盖?
ThinkGem
ThinkGem

引用来自“古有南风”的评论

这个自动生成完还要配mapper文件才能用吗?
基本操作不需要,需要自定义的复杂查询需要写个mapper文件扩展语法。
古有南风
古有南风
这个自动生成完还要配mapper文件才能用吗?
ThinkGem
ThinkGem

引用来自“耕地黄牛”的评论

用4.0之前的版本时有个问题,写手机端接口时当前类(A)的属性字段包含其它类(B),那么查询结果集中缺失了类(B)的所有属性字段;之前解决方法是把类(B)的所需字段直接在类(A)上添加相应属性,现在4.0版本如何解决此问题。
嵌套类对象就可以,之前版本应该也可以吧?类B是类A的一个属性,JsonMapper转换的时候嵌套对象也会序列化JSON的。
耕地黄牛
耕地黄牛
用4.0之前的版本时有个问题,写手机端接口时当前类(A)的属性字段包含其它类(B),那么查询结果集中缺失了类(B)的所有属性字段;之前解决方法是把类(B)的所需字段直接在类(A)上添加相应属性,现在4.0版本如何解决此问题。
jeesite框架思维导图

工欲善其事,必先利其器!工匠想要使他的工作做好,一定要先让工具锋利。要做好一件事,准备工作非常重要。刚刚接触jeesite,觉得还不错,可其技术涉及 1、后端 核心框架:Spring Framework ...

zerov ⋅ 2016/06/27 ⋅ 7

jeesite 扩展手机验证和密码验证

$.validator.addMethod("mobile",function(value,element,params){

wangxujun59 ⋅ 06/12 ⋅ 0

jeesite v4.0.2多数据源配置问题

现在项目管理后台想用jeesite4.0,需要支持多数据源配置。自己配置了一天也不好使。请问有做过类似的同学分享下经验。感激不尽。最好能有详细的配置步骤。谢谢了

crazyYXD ⋅ 05/04 ⋅ 0

解析 Kindle 剪贴文件中的笔记和标记 - clippings-gem

Clippings Clippings 能够解析 Kindle 剪贴文件中的笔记和标记。 安装 Add this line to your application's Gemfile: gem 'clippings' And then execute: $ bundle Or install it yourself......

杜小豆 ⋅ 03/02 ⋅ 0

ThinkGem/JeeSite

JeeSite 企业信息化快速开发平台 平台简介 JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的开源Java EE快速开发平台。 JeeSite是您快速完成项目的最佳基础平台...

ThinkGem ⋅ 2013/08/30 ⋅ 0

中文环境下安装odoo官方blog模块出现日期转换字符编码出错的解决

转载地址:http://www.khcloud.net:4082/?thread-37.htm 昨天想安装一下odoo官方的blog模块,安装过程都正常,但跳转到blog页面时报错: UnicodeDecodeError: 'utf8' codec can't decode by...

siweilai ⋅ 03/02 ⋅ 0

jeesite v4.0.2 版本多数据源配置问题

现在项目管理后台想用jeesite4.0,需要支持多数据源配置。自己配置了一天也不好使。请问有做过类似的同学分享下经验。感激不尽。最好能有详细的配置步骤。谢谢了

crazyYXD ⋅ 05/04 ⋅ 0

Java Web之理解 Hibernate And MyBatis

在JavaWeb开发中,最经典的就是SSH框架组合和SSM框架组合,现在很多IT公司愿意使用SSM,对于这里的H和M即Hibernate和MyBatis,今天简单来说道说道。 班门弄斧 上课时,我经常跟学生说,学习任...

YungFan ⋅ 2017/06/28 ⋅ 0

PussInBoots/Morning

猫宁Morning公益商城系统 但行好事,莫问前程。(基于SSM框架的公益B2C网上商城的设计与实现) QQ群:558243903 紧急求助 本人大四马上毕业了,专业电子商务,非科班生,大三自学Java,急需一...

PussInBoots ⋅ 2016/11/17 ⋅ 0

Hibernate 增强工具包--Hibernate-Plus

简介 | Intro Hibernate 增强工具包 - 只做增强不做改变,更加精简持久层CRUD操作 优点 | Advantages 纯正血统:完全继承原生 Hibernate 的所有特性 最少依赖:仅仅依赖 Hibernate 自动生成代...

青苗 ⋅ 2016/12/06 ⋅ 3

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Yii2中findAll()的正确使用姿势/返回为空的处理办法

从一次错误的操作开始 $buildingObject = Building::findAll("status=1"); 1 这个调用看着没有任何毛病,但是在使用时返回的结果却是一个空数组。再回过头来看看数据表中: 按照套路来讲,查...

dragon_tech ⋅ 今天 ⋅ 0

如何优雅的编程——C语言界面的一点小建议

我们鼓励在编程时应有清晰的哲学思维,而不是给予硬性规则。我并不希望你们能认可所有的东西,因为它们只是观点,观点会随着时间的变化而变化。可是,如果不是直到现在把它们写在纸上,长久以...

柳猫 ⋅ 今天 ⋅ 0

从零手写 IOC容器

概述 IOC (Inversion of Control) 控制反转。熟悉Spring的应该都知道。那么具体是怎么实现的呢?下面我们通过一个例子说明。 1. Component注解定义 package cn.com.qunar.annotation;impo...

轨迹_ ⋅ 今天 ⋅ 0

系统健康检查利器-Spring Boot-Actuator

前言 实例由于出现故障、部署或自动缩放的情况,会进行持续启动、重新启动或停止操作。它可能导致它们暂时或永久不可用。为避免问题,您的负载均衡器应该从路由中跳过不健康的实例,因为它们...

harries ⋅ 今天 ⋅ 0

手把手教你搭建vue-cli脚手架-详细步骤图文解析[vue入门]

写在前面: 使用 vue-cli 可以快速创建 vue 项目,vue-cli很好用,但是在最初搭建环境安装vue-cli及相关内容的时候,对一些人来说是很头疼的一件事情,本人在搭建vue-cli的项目环境的时候也是...

韦姣敏 ⋅ 今天 ⋅ 0

12c rman中输入sql命令

12c之前版本,要在rman中执行sql语句,必须使用sql "alter system switch logfile"; 而在12c版本中,可以支持大量的sql语句了: 比如: C:\Users\zhengquan>rman target / 恢复管理器: Release 1...

tututu_jiang ⋅ 今天 ⋅ 0

Nginx的https配置记录以及http强制跳转到https的方法梳理

Nginx的https配置记录以及http强制跳转到https的方法梳理 一、Nginx安装(略) 安装的时候需要注意加上 --with-httpsslmodule,因为httpsslmodule不属于Nginx的基本模块。 Nginx安装方法: ...

Yomut ⋅ 今天 ⋅ 0

SpringCloud Feign 传递复杂参数对象需要注意的地方

1.传递复杂参数对象需要用Post,另外需要注意,Feign不支持使用GetMapping 和PostMapping @RequestMapping(value="user/save",method=RequestMethod.POST) 2.在传递的过程中,复杂对象使用...

@林文龙 ⋅ 今天 ⋅ 0

如何显示 word 左侧目录大纲

打开word说明文档,如下图,我们发现左侧根本就没有目录,给我们带来很大的阅读障碍 2 在word文档的头部菜单栏中,切换到”视图“选项卡 3 然后勾选“导航窗格”选项 4 我们会惊奇的发现左侧...

二营长意大利炮 ⋅ 今天 ⋅ 0

智能合约编程语言Solidity之线上开发工具

工具地址:https://ethereum.github.io/browser-solidity/ 实例实验: 1.创建hello.sol文件 2.调试输出结果

硅谷课堂 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部