1. 程式人生 > >【ssm框架】列舉類Enum的應用

【ssm框架】列舉類Enum的應用

通常我們會用一個布林值來表示狀態,比如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框架的融合應用。