前端交互:页面之间的交互和交互细节
Restful:前端设计接口之间的一种常用的规范
Spring MVC:框架整合,以及如何应用设计和实现Restful接口
Bootstrap和jquery:前者负责页面布局和样式控制,后者负责交互的实现。
1 前端分析与设计
1.1 前端交互设计部分
前端页面流程:
根据细致的流程逻辑,前端工程师设计页面,后端工程师开发对应的代码,可以使得前端和后端之间相互碰触,更加容易的协调一致。所以,前端交互流程是系统开发中一个很重要的部分。
1.2 Restful接口设计
什么是Restful?
它是一种优雅的URI表述方式,用来设计我们资源的访问URL;通过这个URL的设计,我们就可以很自然的感知到这个URL代表的是哪种业务场景或者什么样的数据或资源。基于Restful设计的URL,对于我们接口的使用者、前端、web系统或者搜索引擎甚至是我们的用户,都是非常友好的。
看看URL设计规范:
关于Restful的了解不再做详细介绍,下面看看我们这个秒杀系统的URL设计:
接下来基于上述资源接口来开始我们对SpringMVC框架的使用。
2 整合配置Spring MVC框架
2.1 Spring MVC运行流程
使用SpringMVC始终是围着着Handle开发,Handler最终的产出就是Model和View,即,模型和视图。下面先回顾一下Spring MVC的运行路程图:
工作原理(运行流程):
1、客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet.
2、DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报文头和请求参数Cookie等)以及HandlerMapping(默认使用DefaultAnnotationHandlerMapping)的配置来映URL,找到处理请求的处理器Handler(每一个请求都对应了一个Handler)。
3-4、DispatcherServlet将处理权交给根据HandlerMapping找到对应Handler(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用:默认使用DefaultAnnotationHandlerAdapter来对上一步的Handler进行适配,匹配到我们自己写的Controller类(如果使用到拦截器,则同样把拦截器绑定到这个流程当中)。
5、Handler对数据处理完成以后将返回一个ModelAndView()对象交付给DispatcherServlet。
6、Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver(利用视图解析器InternalResourceViewResolver)将逻辑视图转化为真正的视图View,并用model来承载数据。
7、Dispatcher通过model对ModelAndView()中的参数进行解析,最终展现出完整的view并返回给客户端。
2.1.1 Http请求映射原理
下面再看一下Http请求地址的映射原理:
用户发送的Http请求,首先会发送到Servlet容器(Tomcat或Jetty),而Spring MVC则使用的是HandlerMapping来映射URL,然后使用Handler方法来最终执行。(默认使用 DefaultAnnotationHandlerMapping注解来映射,也可以通过XML配置编程来映射)
注解映射的技巧:
请求方法的细节处理:
1. 请求参数绑定
2. 请求方式限制
3. 请求转发和重定向
4. 数据模型赋值
5. 返回Json数据
6. Cookie访问
看下面的一个例子:
主要应用了URL书写方式,限制了数据提交方式,判定使用url转发还是重定向,使用model承载数据,返回字符串修改URL链接。
2.1.2如何返回Json数据
2.1.3 Cookie访问
2.2 Spring MVC整合
在WEB-INF项目中配置文件web.xml中配置我们的前端中央控制器DispatcherServlet的配置,也是Spring MVC的核心所在,并加载mybatis配置文件
spring-dao.xml,spring配置文件spring-service.xml、spring-web.xml文件,将三个框架整合起来,文件内容如下:
<!DOCTYPE web-app PUBLIC "-//SunMicrosystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app version="2.4"metadata-complete="true" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <!--用maven创建的web-app需要修改servlet的版本为3.1--> <!--配置DispatcherServlet--> <servlet> <servlet-name>seckill-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--配置SpringMVC 需要配置的文件: spring-dao.xml,spring-service.xml,spring-web.xml Mybites -> spring ->springMvc Mybatis被整合进SPring中,Spring要整合进SPring MVC当中; 不过,Spring MVC本来就出自Spring框架,同属一个框架,已经无缝衔接整合了 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-*.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>seckill-dispatcher</servlet-name> <!--默认匹配所有请求--> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
然后,在Spring容器中进行web层相关的bean配置,即Controller的配置,在Spring包下创建一个spring-web.xml,配置内容如下:
<?xml version="1.0"encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd " > <!--配置spring mvc--> <!--1:开启springmvc注解模式--> <!-- 监护配置 a.自动注册DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter b.默认提供一系列的功能:数据绑定,数字和日期的format@NumberFormat,@DateTimeFormat,xml,json的默认读写支持--> <mvc:annotation-driven/> <!--2:静态资源默认servlet配置--> <!-- 1):加入对静态资源处理:js,gif,png 2):允许使用 "/" 做整体映射 --> <mvc:default-servlet-handler/> <!--3:配置JSP 显示ViewResolver--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <!--4:扫描web相关的bean--> <context:component-scan base-package="org.seckill.web"/> </beans>
如此,便完成了SpringMVC框架的配置,将框架整合到了项目当中,接下来则是开发Controller了,这里是基于Restful接口进行我们的项目的Controller开发。
3 基于Restful的Controller开发
这里Restful接口使用Spring MVC实现的,Controller中的每一个方法都对应我们系统中的一个资源URL,其设计应该遵循Restful接口的设计风格。在org.seckill包下创建一个web包用于放web层Controller开发的代码,在该包下创建一个SeckillController.java :
@Controller @RequestMapping("/seckill") //url:/模块/资源/{id}/细分/seckill/list public class SeckillController { @Autowired private SeckillService seckillService; @RequestMapping(value="/list",method=RequestMethod.GET) public String list(Model model) { List<Seckill> list=seckillService.getSeckillList(); model.addAttribute("list",list); //list.jsp+model=ModelAndView return "lsit"; } @RequestMapping(value="/{seckillId}/detail",method=RequestMethod.GET) public String detail(@PathVariable("seckillId")Long seckillId,Model model){ if(seckillId==null) //请求不存在的时候,直接重定向回到列表页 { return "redirect:/seckill/list"; } Seckill seckill=seckillService.getById(seckillId); if(seckill==null) { //如果请求对象不存在 return "forward:/seckill/list"; } return "detail"; } @RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.POST, produces = { "application/json;charset=UTF-8" }) @ResponseBody //封装成json public SeckillResult<Exposer> exposer(Long seckillId) { SeckillResult<Exposer> result; try { //Exposer:存放是否秒杀的状态信息。 Exposer exposer = seckillService.exportSeckillUrl(seckillId); result = new SeckillResult<Exposer>(true, exposer); } catch (Exception e) { e.printStackTrace(); result = new SeckillResult<Exposer>(false, e.getMessage()); } return result; } /* * md5:验证用户的请求有没有被篡改 * 默认的ajax输出是Json格式,所以将输出结果都封装成Json格式。 */ @RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST, produces = { "application/json;charset=UTF-8" }) @ResponseBody public SeckillResult<SeckillExecution> execute( @PathVariable("seckillId") Long seckillId, @PathVariable("md5") String md5, //required = false表示电话号码不是必须的。 @CookieValue(value = "killPhone", required = false) Long phone) { //Spring MVC valid if (phone == null) { return new SeckillResult<SeckillExecution>(false, "未注册"); } SeckillResult<SeckillExecution> result; try { SeckillExecution execution = seckillService.executeSeckill(seckillId, phone, md5); return new SeckillResult<SeckillExecution>(true, execution); } catch (RepeatKillException e1) { SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.REPEAT_KILL); return new SeckillResult<SeckillExecution>(false, execution); } catch (SeckillCloseException e2) { SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.END); return new SeckillResult<SeckillExecution>(false, execution); } catch (Exception e) { SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.INNER_ERROR); return new SeckillResult<SeckillExecution>(false, execution); } } // 获取系统时间 @RequestMapping(value = "/time/now", method = RequestMethod.GET) public SeckillResult<Long> time() { Date now = new Date(); return new SeckillResult<Long>(true, now.getTime()); } }
Controller中的方法的开发完全是按照Service接口中的方法进行开发的:
第一个方法用于访问我们商品的列表页;
第二个方法访问商品的详情页;
第三个方法用于返回一个json数据,数据中封装了我们商品的秒杀地址;
第四个方法用于封装用户是否秒杀成功的信息;
第五个方法用于返回系统当前时间。
代码中涉及到一个将返回秒杀商品地址封装为json数据的一个Vo类,即SeckillResult.java,在dto包中创建此类:
//所有ajax请求的返回类型,封装为json结果类型 public class SeckillResult<T> //泛型类型的类 { private boolean success; private T data; private String error; public SeckillResult(boolean success, T data) { super(); this.success = success; this.data = data; } public SeckillResult(boolean success, String error) { super(); this.success = success; this.error = error; } //getter and setter……,自行补充 }
到此处,Controller的开发内容完成,剩下的就是对Web页面内容进行开发。
4 基于bootstrap开发页面结构
bootStrap是目前比较受欢迎的前端框架,是基于HTML、CSS、JavaScript的,简洁灵活,使得Web开发更加快捷方便。
BootStrap详细教程可参考:http://www.runoob.com/bootstrap/bootstrap-tutorial.html