zoukankan      html  css  js  c++  java
  • 基于Backbone.js的JavaScript MVC示例程序(2)

    二.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>
  • 相关阅读:
    Qt对文件的删除、复制、移动、可执行文件位置
    qt关于窗口关闭触发函数/信号
    QString.toUtf8().data()的问题 & char *转换到QByteArray注意
    Qt中类型之间的转换
    C++中auto和decltype的区别和功能
    Delphi 系统[11]关键字和保留字 goto、label
    Delphi 系统[10]关键字和保留字 with
    Delphi 系统[9]关键字和保留字 for、to、downto、do、while、repeat、until
    Delphi 系统[8]关键字和保留字 if、then、else、case
    Delphi 系统[7]关键字和保留字 begin、end
  • 原文地址:https://www.cnblogs.com/hiddenfox/p/2640813.html
Copyright © 2011-2022 走看看