SSH这三个巨擘已经现身了,接下来就轮到我们小型的AJAX框架DWR了。做好DWR的准备工作:导入JAR包->在web.xml配置核心Servlet->编写核心配置文件dwr.xml,我在前面的应用中已经详细介绍过DWR,这里就简单地说一下。DWR是一个JAVA世界里的AJAX框架,它对页面表现并没有提供什么支持,它的强大主要体现在和服务器端程序的交互能力以及和Spring这样的大框架的良好集成。有了它,我们能做的事就是,能够使用JavaScript操作后台的JAVA代码。
我们先来看看它在web.xml上的配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- spring config -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/classes/applicationContext.xml
</param-value>
</context-param>
<!-- struts config -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- dwr config -->
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>
org.directwebremoting.servlet.DwrServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>classes</param-name>
<param-value>java.lang.Object</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<!-- encoding filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
然后来看看由Spring管理的业务逻辑层的代码,依然是面向接口编程:
package org.leno.houseHire.service;
import java.util.List;
import org.leno.houseHire.action.Condition;
public interface IHouseService {
public List<HouseDTO> findAllHouse(Condition cond,final int start ,final int limit);
public void addHouse(HouseDTO house);
public void editHouse(HouseDTO house);
public HouseDTO findById(String id);
public int delHouse(List<String> ids);
public long getTotalNums(Condition cond);
public List<AreaDTO> getAllAreas();
public List<StreetDTO> getAllStreets(int aid);
public String getAreaNameById(int id);
public String getStreetNameById(int id);
}
package org.leno.houseHire.service;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
import org.leno.houseHire.action.Condition;
import org.leno.houseHire.dao.Area;
import org.leno.houseHire.dao.House;
import org.leno.houseHire.dao.IHouseDAO;
import org.leno.houseHire.dao.Street;
import org.leno.houseHire.dao.User;
public class HouseServiceImpl implements IHouseService{
private IHouseDAO houseDAO;
public void setHouseDAO(IHouseDAO houseDAO) {
this.houseDAO = houseDAO;
}
public void addHouse(HouseDTO dto) {
House pojo =new House();
try {
BeanUtils.copyProperties(pojo, dto);
Street street = houseDAO.getStreetById(dto.getStreetId());
pojo.setStreet(street);
User user = houseDAO.getUserById(dto.getUserId());
pojo.setUser(user);
pojo.setBooktime(new SimpleDateFormat("yyyy-MM-dd").parse(dto.getBooktimeInfo()));
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
houseDAO.addHouse(pojo);
}
public void editHouse(HouseDTO dto) {
House pojo =new House();
try {
BeanUtils.copyProperties(pojo, dto);
Street street = houseDAO.getStreetById(dto.getStreetId());
pojo.setStreet(street);
User user = houseDAO.getUserById(dto.getUserId());
pojo.setUser(user);
pojo.setBooktime(new SimpleDateFormat("yyyy-MM-dd").parse(dto.getBooktimeInfo()));
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
houseDAO.editHouse(pojo);
}
public List<HouseDTO> findAllHouse(Condition cond,final int start ,final int limit) {
List<House> listPojo = houseDAO.findAllHouse(cond,start,limit);
List<HouseDTO> listDTO = new ArrayList<HouseDTO>();
Iterator<House> it = listPojo.iterator();
while(it.hasNext()){
House house = it.next();
HouseDTO dto = new HouseDTO();
try {
BeanUtils.copyProperties(dto, house);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dto.setBooktimeInfo(new SimpleDateFormat("yyyy-MM-dd").format(house.getBooktime()));
dto.setUserId(house.getUser().getUid());
dto.setUserName(house.getUser().getUname());
dto.setStreetId(house.getStreet().getSid());
dto.setStreetName(house.getStreet().getSname());
dto.setAreaId(house.getStreet().getArea().getAid());
dto.setAreaName(house.getStreet().getArea().getAname());
dto.setAreaStreet(house.getStreet().getArea().getAname()+dto.getStreetName());
dto.setRoomTing(dto.getRoom()+"室"+dto.getTing()+"厅");
listDTO.add(dto);
}
return listDTO;
}
public long getTotalNums(Condition cond) {
return houseDAO.getTotalNums(cond);
}
public List<AreaDTO> getAllAreas() {
List<Area> listPojo = houseDAO.getAllAreas();
List<AreaDTO> listDTO = new ArrayList<AreaDTO>();
Iterator<Area> it = listPojo.iterator();
while(it.hasNext()){
Area house = it.next();
AreaDTO dto = new AreaDTO();
try {
BeanUtils.copyProperties(dto, house);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
listDTO.add(dto);
}
return listDTO;
}
public List<StreetDTO> getAllStreets(int aid) {
List<Street> listPojo = houseDAO.getAllStreets(aid);
List<StreetDTO> listDTO = new ArrayList<StreetDTO>();
Iterator<Street> it = listPojo.iterator();
while(it.hasNext()){
Street house = it.next();
StreetDTO dto = new StreetDTO();
try {
BeanUtils.copyProperties(dto, house);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
listDTO.add(dto);
}
return listDTO;
}
public int delHouse(List<String> ids) {
return houseDAO.delHouse(ids);
}
public String getAreaNameById(int id) {
return houseDAO.getAreaNameById(id);
}
public String getStreetNameById(int id) {
return houseDAO.getStreetNameById(id);
}
public HouseDTO findById(String id) {
int intId = Integer.parseInt(id);
House pojo = houseDAO.findById(intId);
HouseDTO dto = new HouseDTO();
try {
BeanUtils.copyProperties(dto, pojo);
dto.setStreetId(pojo.getStreet().getSid());
dto.setStreetName(pojo.getStreet().getSname());
dto.setAreaId(pojo.getStreet().getArea().getAid());
dto.setAreaName(pojo.getStreet().getArea().getAname());
dto.setUserId(pojo.getUser().getUid());
dto.setUserName(pojo.getUser().getUname());
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dto;
}
}
大家注意,在这里我们的服务层代码并不仅仅只是调用数据访问层代码那么简单,它还需要进行传值组件的转化。细心的同志们已经注意到,在我们的DAO里操作的主要是POJO类,而在我们的Service里面要做的就是DTO和POJO的转化工作。因为表现层的代码只会直接和DTO打交道。这就是严格的JavaEE分层。说到这里,可能有人开始迷惑了。我们这里说明一下:在javaEE企业级开发中,我们一般提倡四层架构体系:WEB表现层->业务逻辑层(服务层)->持久层(数据访问层)->数据库层,我们这里分别使用Struts,Spring,Hibernate来充当前三个层次的框架。一般我们把Action归为Struts所在表现层,Service归为Spring所在业务逻辑层(实际上,Spring是一个系统级别的框架,它的内涵和外延都比另外两个框架要来的大!),DAO归为Hibernate所在持久层,而在每一层上都有特定的传值组件(呵呵,有人不喜欢用大词,通俗点说,所谓传值组件在javaEE体系中就是在页面和数据库之间帮忙传递数据的用JAVA写的类!),我们自动,Struts里有ActionForm,Hibernate里有POJO,那在Spring管辖的业务逻辑层,主要就是DTO。所以我们的数据经常在这3个传值组件之间传递。这里大家可以停下来好好思考一下,会非常有好处。
下面是一些用到的小型DTO类:
package org.leno.houseHire.service;
public class HouseDTO extends HouseSmallDTO{
// Fields
private Integer hid;
private Integer areaId;
private String areaName;
private Integer streetId;
private String streetName;
private Integer userId;
private String userName;
private String title;
private Double hireprice;
private String booktimeInfo;
private String linkman;
private String linktel;
private String housething;
private Integer room;
private Integer ting;
private String areaStreet;
private String roomTing;
public Integer getHid() {
return hid;
}
public void setHid(Integer hid) {
this.hid = hid;
}
public Integer getStreetId() {
return streetId;
}
public void setStreetId(Integer streetId) {
this.streetId = streetId;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Double getHireprice() {
return hireprice;
}
public void setHireprice(Double hireprice) {
this.hireprice = hireprice;
}
public String getLinkman() {
return linkman;
}
public void setLinkman(String linkman) {
this.linkman = linkman;
}
public String getLinktel() {
return linktel;
}
public void setLinktel(String linktel) {
this.linktel = linktel;
}
public String getHousething() {
return housething;
}
public void setHousething(String housething) {
this.housething = housething;
}
public Integer getRoom() {
return room;
}
public String getBooktimeInfo() {
return booktimeInfo;
}
public void setBooktimeInfo(String booktimeInfo) {
this.booktimeInfo = booktimeInfo;
}
public void setRoom(Integer room) {
this.room = room;
}
public Integer getTing() {
return ting;
}
public void setTing(Integer ting) {
this.ting = ting;
}
public String getAreaStreet() {
return areaStreet;
}
public void setAreaStreet(String areaStreet) {
this.areaStreet = areaStreet;
}
public String getRoomTing() {
return roomTing;
}
public void setRoomTing(String roomTing) {
this.roomTing = roomTing;
}
public Integer getAreaId() {
return areaId;
}
public void setAreaId(Integer areaId) {
this.areaId = areaId;
}
public String getAreaName() {
return areaName;
}
public void setAreaName(String areaName) {
this.areaName = areaName;
}
}
package org.leno.houseHire.service;
public class AreaDTO {
private int aid;
private String aname;
public int getAid() {
return aid;
}
public void setAid(int aid) {
this.aid = aid;
}
public String getAname() {
return aname;
}
public void setAname(String aname) {
this.aname = aname;
}
}
package org.leno.houseHire.service;
public class StreetDTO {
private int sid;
private String sname;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
package org.leno.houseHire.service;
public class LoginDTO {
private Integer uid;
private String uname;
private String upass;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
}
这些类都非常简单了。接下来,看看DWR框架的核心配置文件dwr.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://www.getahead.ltd.uk/dwr/dwr20.dtd">
<dwr>
<allow>
<convert converter="bean" match="org.leno.houseHire.service.HouseDTO" />
<convert converter="bean" match="org.leno.houseHire.service.AreaDTO" />
<convert converter="bean" match="org.leno.houseHire.service.StreetDTO" />
<create javascript="houseService" creator="spring">
<param name="beanName" value="houseService">
</param>
<include method="getAllAreas"/>
<include method="getAllStreets"/>
<include method="delHouse"/>
<include method="findById"/>
<include method="getAllStreets"/>
</create>
</allow>
</dwr>
这里create和convert的配置大家注意下,所谓create就是创建一个JavaScript类和Java类的关联映射。我们这里只有一个创建器,它会在客户端本地动态生成一个houseService.js文件,然后它对应Spring框架管理的一个名为houseService的Bean,主要客户端只要引用houseService.js这个文件,就能调用到服务器端houseService的方法。那么,要是我只想向外界公开少数几个方法呢?(涉及到安全问题),我们就可以用include配置了。那么,这不就行了吗?还需要convert干什么呢?恩,等一下。如果我们要在服务器端给客户端传递一个DTO对象,或者是放置着若干DTO对象的集合对象时。或者反过来,我们在客户端给服务器端传递一个JavaScript对象时。DWR怎么做JavaScript对象和DTO对象之间的解析?如果你不给它相关信息,它是做不到的,这就是convert的作用了。也就是说,create指定的对象被创建,convert指定的对象(客户端和服务器端之间携带传递的参数)被转换!
下面是dwr的调试窗口页面(我们在web.xml上指定debug为true,如果产品发布时,要改为false):