今天给项目做一个省市区三级联动的功能模块,想起以前的写过的比较粗糙的实现方式,忽然觉得,有必要把这次的实现方式记录下来,给自己留个方便,也给需要的朋友留个方便。如果看到的朋友觉得好,帮忙给个赞
------------------------------------------------------------------------------------------------------------------------------
原理很简单,打开页面时加载省份的数据,当省份发生变化时,触发事件获取对应省份的城市,并显示在省份后面,
同理,当城市发生变化时,触发事件获取对应的区县并显示在城市的后面。
考虑到以前按部就班的实现方式,这次对代码进行了优化,希冀实现模块化,以便于提升可用性、重用性,减少服务器消耗的资源(资源再少也是肉啊~)。
↓↓↓↓↓↓↓↓ 废话不多说,开始上代码。↓↓↓↓↓↓↓↓
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:[email protected] * @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() 就可以了,而且这种缓存方式比较直观,实用。
受于技术限制,若有不妥当之处,欢迎留言指正。