您的位置:首页 > Web前端 > JavaScript

基于Backbone.js的JavaScript MVC示例程序(2)

2013-10-29 14:54 211 查看
一.概述
二.REST Server的实现
2.1 REST API设计
2.2 数据库设计
2.3 用MyBatis实现的DAO层
2.4 用Jersey实现的REST API
2.5 用Spring AOP实现的日志功能
三.前端的实现
3.1 显示User列表
3.2 显示User详细信息
3.3 修改User信息
3.4 增加User
3.5 删除User
3.6 添加validate

二.REST Server的实现

Server端使用Java来实现,用到了Spring、Mybatis、c3p0、Jersey等技术。
代码结构如下图所示:



2.1 REST API设计

根据系统的功能设计了如下一些REST API:

功能
Method
URL
获取User信息列表
GET
/rest/user
获取某个User的详细信息
GET
/rest/user/[id]
添加一个User
POST
/rest/user
修改某个User的信息
PUT
/rest/user/[id]
删除某个User
DELETE
/rest/user/[id]
验证Username是否合法
GET
/rest/user/validate/[username]
其中POST请求的JSON中没有User的id,因为在数据库中这是自增的字段,所以在insert成功之后,需要将id设置上之后再返回整个JSON对象,方便前端更新数据。
最后一个方法是用来检测用户名是否已经被注册的,返回true或者false,用来进行表单验证。

2.2 数据库设计

数据库使用的是SQLServer,只有一张表,字段也比较少,创建数据表的SQL如下:

CREATE TABLE [dbo].[rd_user](
  [id] [int] IDENTITY(1,1) NOT NULL,
  [username] [varchar](50) NOT NULL,
  [password] [varchar](50) NOT NULL,
  [email] [varchar](50) NOT NULL,
  [phone] [varchar](50) NULL
) ON [PRIMARY];


2.3 用MyBatis实现的DAO层

连接池采用了c3p0,在Spring中的配置如下:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="${jdbc.driver}" />
        <property name="jdbcUrl" value="${jdbc.url}"/>            
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="minPoolSize" value="5"></property>
        <property name="maxPoolSize" value="30"></property>
        <property name="initialPoolSize" value="5"></property>
        <property name="maxIdleTime" value="60"></property>
        <property name="acquireIncrement" value="5"></property>
</bean>


在Spring中配置MyBatis:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
</bean>


在Spring中注册DAO的bean:

<bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.demo.register.dao.mybatis.MyBatisUserDao"></property>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>


User的POJO:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private String phone;
    //省略getter setter
}


IUserDao接口:

public interface IUserDao {
    public User getUserById(int id);
    public User getUserByUsername(String username);
    public List<User> getUserList();
    public void insert(User user);
    public void update(User user);
    public void deleteUserById(int id);
}


MyBatisUserDao接口,继承自IUserDao,使用Mybatis的annotation实现增删改查功能,但是有些复杂的查询必须使用XML。

public interface MyBatisUserDao extends IUserDao {

    @Select("SELECT * FROM rd_user WHERE id = #{id}")
    public User getUserById(@Param("id") int id);
   
    @Select("SELECT * FROM rd_user WHERE username = #{username}")
    public User getUserByUsername(@Param("username") String username);
   
    @Select("SELECT * FROM rd_user order by id")
    public List<User> getUserList();
   
    @Insert("INSERT INTO rd_user(username, password, phone, email) " +
            "VALUES(#{username}, #{password}, #{phone}, #{email})")
    //Insert成功之后会将id更新到User的对象
    @SelectKey(statement="SELECT @@IDENTITY", keyProperty="id", before=false, resultType=int.class)
    public void insert(User user);

    @Update("UPDATE rd_user " +
            "SET username=#{username}, password=#{password}, phone=#{phone}, email=#{email} " +
            "WHERE id=#{id}")
    public void update(User user);
   
    @Delete("DELETE FROM rd_user WHERE id = #{id}")
    public void deleteUserById(@Param("id") int id);

}


2.4 用Jersey实现的REST API

在Web.xml中整合Jersey和Spring:

<servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>com.demo.register.rest</param-value>
        </init-param>
</servlet>
<servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
</servlet-mapping>


关于Jersey的使用参看官网的文档:http://jersey.java.net/nonav/documentation/latest/user-guide.html
UserAPI的实现类:

package com.demo.register.rest;

import java.util.List;
 
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

 
import com.demo.register.bean.User;
import com.demo.register.dao.IUserDao;

@Path("/user")
public class UserAPI {
    private IUserDao userDao;
   
    public IUserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(IUserDao userDao) {
        this.userDao = userDao;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<User> getUserList() {
        return userDao.getUserList();
    }
   
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public User addUser(User user) {
        userDao.insert(user);
        return user;
    }
   
    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public User getUser(@PathParam("id") int id) {
        return userDao.getUserById(id);
    }

    @PUT
    @Path("/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public String updateUser(User user) {
        userDao.update(user);
        return "{\"success\":\"true\"}"; //这里如果不加双引号,前端的JS不会将它识别为JSON,而且会产生error事件
    }

    @DELETE
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public String deleteUser(@PathParam("id") int id) {
        userDao.deleteUserById(id);
        return "{\"success\":\"true\"}";
    }

    @GET
    @Path("/validate/{username}")
    @Produces(MediaType.TEXT_PLAIN)
    public String validate(@PathParam("username") String username) {
        return userDao.getUserByUsername(username) == null ? "true" : "false";
    }
}


当然还需要在Spring中给UserAPI加上对UserDao的依赖,我试了一下这个userDao不能自动注入,我觉得是因为注册bean的class是MyBatis里面的类而不是IUserDao的子类,或许还有我不知道的方法:

<bean id="userAPI" class="com.demo.register.rest.UserAPI">
        <property name="userDao" ref="userDao"/>
</bean>


2.5 用Spring AOP实现的日志功能

使用Spring AOP对所有的REST API相关方法输出日志。首先需要一个日志类,然后再将这个日志类编织到REST API的相关方法。使用这样的方法就不需要在每个REST API的方法中各自输出日志了。
日志的实现类:

package com.demo.register.log;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;

public class RestLogger {
    //为每个类创建一个Log
    private static final Map<Class<?>, Log> LOG_MAP = new HashMap<Class<?>, Log>();
    
    private Log getLogger(Class<?> clazz) {
        Log log = (Log) LOG_MAP.get(clazz);
        if (log == null) {
            log = LogFactory.getLog(clazz);
            LOG_MAP.put(clazz, log);
        }
        return log;
    }
    
    public Object profileMethod(ProceedingJoinPoint call) throws Throwable {
        Log log = getLogger(call.getTarget().getClass());

        if (log.isDebugEnabled()) {
            log.debug("method call: " + call.getSignature().toString()); //输出调用的方法
            log.debug("method parameter: " //输出参数
                    + ReflectionToStringBuilder.toString(call.getArgs(),
                        ToStringStyle.SHORT_PREFIX_STYLE, true));
            try {
                Object rt = call.proceed(); //调用原方法

                log.debug("method return: " //输出方法的返回值
                        + ReflectionToStringBuilder.toString(rt,
                                ToStringStyle.SHORT_PREFIX_STYLE, true));

                return rt;
            } catch (Throwable e) {
                log.error("method exception: " + e.getMessage(), e);
                throw e;
            } 
        } else {
            return call.proceed();
        }
    }

}


在Spring中配置AOP

<bean id="restLogger" class="com.demo.register.log.RestLogger" ></bean>

    <aop:config>
        <aop:aspect ref="restLogger">
            <aop:pointcut id="restMethod" expression="execution(* com.demo.register.rest.*.*(..))" />
            <aop:around pointcut-ref="restMethod" method="profileMethod" />
        </aop:aspect>
    </aop:config>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: