通常我们会用一个布尔值来表示状态,比如0表示不通过,1表示通过,然而,许多时候状态并不只有两种,比如在系统中表示毕业论文的答辩状态,通常有正常答辩,争优答辩,延期答辩3种,在数据库中我们使用的是整数来存储,0表示正常答辩,2表示争优答辩,4表示延期答辩,那么如何实现这种对应关系呢?
/**
* @描述: 所有枚举类型都继承此接口,即可自动处理枚举类型的映射
* @作者:https://github.com/xjs1919/enumhandler
* @日期:2016-08-09 15:28
* @版本: v1.0
*/
public interface Identifiable<K> {
K getId();
}
/**
* @描述: 枚举类型字段的通用处理类
* @作者:https://github.com/xjs1919/enumhandler
* @日期:2016-08-09 15:30
* @版本: v1.0
*/
@Alias("EnumHandler")
public class EnumHandler<E extends Enum<E> &Identifiable<K>, K> extends BaseTypeHandler<E> {
/**
* 枚举类型的实际类型
*/
private Class<E> type;
public EnumHandler(Class<E>type) {
if(type == null){
throw newIllegalArgumentException("Type argument cannot be null");
}
this.type = type;
}
/**
* 非NULL情况,怎么设参数还得交给不同的子类完成
* @param ps
* @param i
* @param parameter
* @param jdbcType
* @throws SQLException
*/
@Override
public voidsetNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcTypejdbcType) throws SQLException {
if(jdbcType == null){
K id = parameter.getId();
if(id instanceof Integer ||id instanceof Short || id instanceof Character || id instanceof Byte){
ps.setInt(i,(Integer)id);
}else if(id instanceofString){
ps.setString(i,(String)id);
}else if(id instanceofBoolean){
ps.setBoolean(i, (Boolean)id);
}else if(id instanceof Long){
ps.setLong(i, (Long)id);
}else if(id instanceofDouble){
ps.setDouble(i,(Double)id);
}else if(id instanceofFloat){
ps.setFloat(i, (Float)id);
}else{
throw newRuntimeException("unsupported [id] type of enum");
}
}else{
ps.setObject(i,parameter.getId(), jdbcType.TYPE_CODE);
}
}
/**
* 根据列名,获取可以为空的记录
* @param rs
* @param columnName
* @return
* @throws SQLException
*/
@Override
public E getNullableResult(ResultSetrs, String columnName) throws SQLException {
String s =rs.getString(columnName);
return toEnum(s);
}
/**
* 根据列索引,获取可以为空的记录
* @param rs
* @param columnIndex
* @return
* @throws SQLException
*/
@Override
public E getNullableResult(ResultSetrs, int columnIndex) throws SQLException {
String s =rs.getString(columnIndex);
return toEnum(s);
}
@Override
public EgetNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String s =cs.getString(columnIndex);
return toEnum(s);
}
private E toEnum(String id){
EnumSet<E> set =EnumSet.allOf(type);
if (set == null || set.size()<= 0) {
return null;
}
for (E e : set) {
K k = e.getId();
if(k != null){
if(k.toString().equals(id)){
return e;
}
}
}
return null;
}
}
在mybatis中有一个功能强大的typeHandler专门用来解决数据库中的数据类型和Java中的数据类型之间的转化问题,我们通过定义EnumHandler,继承BaseTypeHandler,实现其中的抽象方法即可。
之后定义枚举类,实现上面的接口,泛型类型为数据库中存储的类型
public enum DefenseStatus implementsIdentifiable<Integer>{
NORMAL(0, "正常答辩"),
EXCEL(2, "争优答辩"),
DELAY(4, "延期答辩");
private Integer val;
private String label;
DefenseStatus(Integer val, Stringlabel) {
this.val = val;
this.label = label;
}
public static DefenseStatusgetById(int id){
DefenseStatus[] statuses =DefenseStatus.values();
for(DefenseStatus status :statuses){
if(status.val == id){
return status;
}
}
return null;
}
@Override
public Integer getId() {
return this.val;
}
@JsonValue
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return label;
}
}
然后我们就可以使用这个handler来完成我们的转换了。在mapper.xml定义resultMap的时候,凡是枚举类那一项,就写成下面这种格式,其中的typeHandler换成EnumHandler的具体路径即可。
<result column="grouptype"property="grouptype" typeHandler="com.mankind.thesis.common.mybatis.EnumHandler"/>
在insert,delete,update等这些语句中如果有用到枚举类作为传入参数,则替换为即可
#{grouptype,typeHandler=com.mankind.thesis.common.mybatis.EnumHandler}
上面讲到的都是与数据库之间的交互,那么与controller与前台的交互呢?我如何让前台传一个0/2/4过来,就自动转换成对应的枚举类型呢?这同样需要我们去实现数据绑定。在BaseController中加入下面这段代码即可。
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(DefenseStatus.class, newPropertyEditorSupport(){
@Override
public void setAsText(Stringtext) throws IllegalArgumentException {
int val = 0;
try {
val =Integer.parseInt(text);
}catch (Exception ex){
}
setValue(DefenseStatus.getById(val));
}
});
}
这样在前端传入defenseStatus=0,而后台的方法参数中有
DefenseStatus defenseStatus时,参数将自动绑定为对应的枚举类,我们可以直接使用枚举类进行操作。
而如果我们需要将枚举类传到前台进行展示(通常是作为检索条件的单选框出现),只需要在controller中写上
@RequestMapping(value = "/add",produces = "text/html;charset=utf-8", method = RequestMethod.GET)
public String add(Model model, Long taskid) throws Exception {
model.addAttribute("defenseTask",defenseTaskService.queryById(taskid));
model.addAttribute("titles", TitleLevel.values());
model.addAttribute("defenseStatuses",DefenseStatus.values());
return"console/thesis/defense/group/add";
}
前端代码:
<select id="cc"class="easyui-combobox" name="type"editable="false" style="width:200px;">
<c:forEach items="${ defenseStatuses }"var="type">
<option value="${type.ordinal()}"}>${type.label}</option>
</c:forEach>
</select>
以上便是Enum枚举类与ssm框架的融合应用。