今天给项目做一个省市区三级联动的功能模块,想起以前的写过的比较粗糙的实现方式,忽然觉得,有必要把这次的实现方式记录下来,给自己留个方便,也给需要的朋友留个方便。如果看到的朋友觉得好,帮忙给个赞
------------------------------------------------------------------------------------------------------------------------------
原理很简单,打开页面时加载省份的数据,当省份发生变化时,触发事件获取对应省份的城市,并显示在省份后面,
同理,当城市发生变化时,触发事件获取对应的区县并显示在城市的后面。
考虑到以前按部就班的实现方式,这次对代码进行了优化,希冀实现模块化,以便于提升可用性、重用性,减少服务器消耗的资源(资源再少也是肉啊~)。
↓↓↓↓↓↓↓↓ 废话不多说,开始上代码。↓↓↓↓↓↓↓↓
1.先布局前端DIV,需要的选择的是省份、城市、区县,当然,咱们不能弄的太难看,再附上CSS样式
<!----------------------- 省市区三级联动布局 ----------------------->
<div id="china_pca">
<div id="china_p" class="china_p">
<font class="china_f">省份:</font>
<select class="china_s" id="province" name="province">
<option>请选择省份</option>
<c:forEach items="${provincelist }" var="province">
<option value="${province.code }">${province.name }</option>
</c:forEach>
</select>
</div>
<div id="china_c" class="china_ca">
<font class="china_f">城市:</font>
<select class="china_s" id="city" name="city">
</select>
</div>
<div id="china_a" class="china_ca">
<font class="china_f">区县:</font>
<select class="china_s" id="area" name="area">
</select>
</div>
</div>
/**************************** 省市区三级联动 ****************************/
#china_pca{height: 50px;width: 550px;}
.china_p{width: 150px;float:left;margin-right: 6px;}
.china_ca{width: 150px;float:left;margin-right: 6px;display: none;}
.china_f{color:#457887;font-size: 15px;width: 50px;}
.china_s{width: 100px;border-radius: 8px 8px 8px 8px;}
完成DIV和CSS后,就开始做主要的交互了,需要达到的效果的是,选择省份的时候,不能显示城市与区县;
选择城市的时候,不能显示区县。
2.用JQuery给选择标签绑定change事件,通过Ajax获取对应的城市或者区县的数据。城市和区县的数据获取
方式是一致的,秉持精良精简的原则,便有了下面的JS代码,以及对应的后端方法。
/********************************* 省市区三级联动 *********************************/
$("#province").change(function(){
$("#china_c").css({"display":"none"});
$("#china_a").css({"display":"none"});
var province=$(this).children('option:selected').val();
showCityArea(province,'city');
})
$("#city").change(function(){
$("#china_a").css({"display":"none"});
var province=$(this).children('option:selected').val();
showCityArea(province,'area');
})
function showCityArea(chinacode,chinatype){
$.ajax({
type : "post",
url : host+"find/cityarea",
data : {code:chinacode,type:chinatype},
dataType : 'json',
success : function(data,status){
if(status=="success"){
if(data==null){alert("出错啦,请联系技术人员");return;}
if(chinatype=="city"){var str="<option value=\"0\">请选择城市</option>";}
if(chinatype=="area"){var str="<option value=\"0\">请选择区县</option>";}
for(var i=0;i<data.length;i++){
str+="<option value=\""+data[i].code+"\">"+data[i].name+"</option>";
}
$("#"+chinatype+"").html(str);
if(chinatype=="city"){$("#china_c").css({"display":"block"});}
if(chinatype=="area"){$("#china_a").css({"display":"block"});}
}
}
})
}
Controller中的对应的方法:
/**
* @author JQ.Wang E-mail:wang53400487@hotmail.com
* @date 创建时间:2015年8月6日 下午6:18:07
* @version 1.0
* @parameter
* @since JDK1.7
* @return
*/
@Controller
public class IndexController extends ApplicationController{
protected static final Logger logger=Logger.getLogger(IndexController.class);
@Autowired
private DataMessageService dataMessageService;
/**
* 示例:内容传递 省市区三级联动实现
* 方法参数使用HttpServletRequest实现内容传递
* 需要使用省市区三级联动的页面,在路径控制Controller中加入下面所示代码块即可
* @param request
* @return
*/
@RequestMapping("/say")
public String say(HttpServletRequest request){
//省市区三级联动 调用
List<ChinaProvince> provincelist=DZSession();
request.setAttribute("provincelist", provincelist);
return "SayHello";
}
/**
* 示例:ajax前后端交互 对象转换成json
* 通过定义路径,访问类型,对应的传入参数,
* 添加 ResponseBody 注解
* 使用HttpServletResponse实现前后端的交互
* @param code
* @param type
* @param response
* @return
*/
@RequestMapping(value={"/find/cityarea"},method=RequestMethod.POST)
public @ResponseBody String getCityArea(@RequestParam("code")String code,
@RequestParam("type")String type,HttpServletResponse response){
response.setContentType("html/text;charset=utf-8");
if (type.equals("city")) {
List<ChinaCity> cityList=Cache.getCityList(code);
return Cache.toJson(cityList);
}
if (type.equals("area")) {
List<ChinaArea> areaList=Cache.getAreaList(code);
return Cache.toJson(areaList);
}
return null;
}
}
@Controller
public class ApplicationController {
protected static final Logger logger=Logger.getLogger(IndexController.class);
@Autowired
private ChinaProvinceService chinaProvinceService;
@Autowired
private ChinaCityService chinaCityService;
@Autowired
private ChinaAreaService chinaAreaService;
/**
* 地址区域缓存,获取省份列表
* 优先级从缓存中获取省市区信息
* 识别是否需要从数据库中获取省市区信息
* @return List
*/
public List<ChinaProvince> DZSession(){
/***** 省市区三级联动 代码块 ************/
List<ChinaProvince> provincelist=Cache.cpProvince;
List<ChinaCity> citylist=Cache.cpCity;
List<ChinaArea> arealist=Cache.cpArea;
if (provincelist.isEmpty()) {
provincelist=chinaProvinceService.findAll();
Cache.cpProvince=provincelist;
}
if (citylist.isEmpty()) {
citylist=chinaCityService.findAll();
Cache.cpCity=citylist;
}
if (arealist.isEmpty()) {
arealist=chinaAreaService.findAll();
Cache.cpArea=arealist;
}
logger.info("=======================省:"+provincelist.size());
logger.info("=======================市:"+citylist.size());
logger.info("=======================区:"+arealist.size());
return provincelist;
}
}
还有关键的缓存设置:
public class Cache {
protected static final Logger log=Logger.getLogger(Cache.class);
//省市区信息
public static List<ChinaProvince> cpProvince=new ArrayList<ChinaProvince>();
public static List<ChinaCity> cpCity=new ArrayList<ChinaCity>();
public static List<ChinaArea> cpArea=new ArrayList<ChinaArea>();
//Jackson框架-转Json所需对象
public static ObjectMapper objectMapper=new ObjectMapper();
/**
* 获取所在省的所有市
* @param provinceCode
* @return List
*/
public static List<ChinaCity> getCityList(String provinceCode){
List<ChinaCity> cc=new ArrayList<ChinaCity>();
for (ChinaCity c : cpCity) {
if (c.getProvincecode().equals(provinceCode)) {
cc.add(c);
}
}
return cc;
}
/**
* 获取所在市的所有区县
* @param cityCode
* @return List
*/
public static List<ChinaArea> getAreaList(String cityCode){
List<ChinaArea> cc=new ArrayList<ChinaArea>();
for (ChinaArea c : cpArea) {
if (c.getCitycode().equals(cityCode)) {
cc.add(c);
}
}
return cc;
}
/**
* List转换Json
* @param param
* @return String
*/
public static String toJson(List<?> param){
if (param==null||param.isEmpty()) {
return null;
}
String jsonStr=null;
try {
jsonStr = objectMapper.writeValueAsString(param);
} catch (IOException e) {
e.printStackTrace();
}
log.info("==============================jsonStr:"+jsonStr);
return jsonStr;
}
}
完成以上这些代码后,发现如果某个页面需要选择区域,只需继承ApplicationController,
调用 DZSession() 就可以了,而且这种缓存方式比较直观,实用。
受于技术限制,若有不妥当之处,欢迎留言指正。