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>
  • 相关阅读:
    086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结
    085 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 04 构造方法调用
    jQuery UI组件库Kendo UI使用技巧小分享
    Kendo UI ListView模板功能,让Web开发更轻松
    UI组件套包DevExpress ASP.NET Core v20.2新版亮点:全新的查询生成器
    Devexpress WinForms最新版开发.NET环境配置Visual Studo和SQL Server对应版本
    全新的桌面应用数据可视化呈现方式,Sankey Diagram控件你了解多少?
    java中的递归方法
    连接数据库查询 将查询结果写入exce文件中
    java连接mysql数据查询数据
  • 原文地址:https://www.cnblogs.com/hiddenfox/p/2640813.html
Copyright © 2011-2022 走看看