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

二.REST Server的实现

Server端使用Java来实现,用到了Spring、Mybatis、c3p0、Jersey等技术。

代码结构如下图所示:

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

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>

你可能感兴趣的:(JavaScript)