這次是事兒B地想要統一控制前後端的數據字典名稱。
在做後臺管理系統時,通常會遇見很多數據字典。例如,學生的性別(男/女)、政治面貌(黨員/團員/羣衆)等。在新增和編輯時,這類字段通常以下拉列表的形式呈現;而下拉列表的內容可以直接在後端查詢並使用模板引擎渲染,也可以異步查詢、JS動態渲染。
@Controller
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
@Autowired
private DictionaryService dictionaryService;
@GetMapping("/view/{id}")
public String view(@PathVariable Integer id) {
model.addAttribute("student", studentService.getById(id));
model.addAttribute("sexes", dictionaryService.findItemsBy("sex"));
model.addAttribute("politics", dictionaryService.findItemsBy("politic"));
}
}
上述代碼是在請求頁面時就查詢字典項,利用模板引擎渲染完畢之後再返回給前端。這裏存在一個問題:如果字典sex
有很多地方用到了,某天我決定給他換個名稱(比如xingbie
),那就得一處一處地改代碼。於是我將所有字典名稱寫在一個接口類中:
public interface AppConstant {
String DICT_SEX = "sex";
String DICT_POLITIC = "politic";
}
所有代碼都通過接口類來選擇字典:
@GetMapping("/view/{id}")
public String view(@PathVariable Integer id) {
model.addAttribute("student", studentService.getById(id));
model.addAttribute(AppConstant.DICT_SEX + "es", dictionaryService.findItemsBy(AppConstant.DICT_SEX));
model.addAttribute(AppConstant.DICT_POLITIC + "s", dictionaryService.findItemsBy(AppConstant.DICT_POLITIC));
}
這樣,當字典名稱發生變更時,只需要修改一處即可。
但問題又來了,後端的字典名稱統一了,傳給前端的字典名稱依舊是千變萬化,前端被迫將字典名稱寫死在代碼中:
<!-- Thymeleaf -->
<select class="form-control" id="sex" readonly>
<!-- student.sex爲整型:0-男,1-女 -->
<option th:each="e : ${sexes}" th:text="${e.val}" th:selected="${e.name eq (student.sex + '')}"></option>
</select>
考慮到JSP能夠直接調用Java類的靜態成員,SpEL也提供了類似的功能:T(com.xx.xx.AppConstant).DICT_SEX
。然後我將所有字典以Map<String, List<DictionaryItem>>
的形式打包後再傳給前端,通過SpEL的map[KEY]
獲取對應的字典:
<!-- Thymeleaf -->
<select class="form-control" id="sex" readonly>
<option th:each="e : ${dictionaryTable[T(com.xx.AppConstant).DICT_SEX + 'es']}"
th:text="${e.val}"
th:selected="${e.name eq (student.sex + '')}"></option>
</select>
最初,我是想直接使用
${T(com.xx.xx.AppConstant).DICT_SEX}
等價${sex}
獲取後端傳遞過來的sex
參數,但發現前者實際上就是一個字符串。所以變通了一下,將其作爲鍵名,將字典打包成Map
。