一.思路:<Springmvc的架构图>
<springmvc处理流程>
二,处理器实现接口controller
所有动作处理实现controller接口调用handlerRequest方法,来实现一个实体的所有增删改查的操作
/**
*拦截器实现的接口
*/
public interface Controller {
/**
* 拦截器中处理请求uri
* @param request
* @param response
* @return
*/
public String handlerRequest(HttpServletRequest request,HttpServletResponse response);
}
假设一个实例实现这个接口<创建一个实例拦截器>
public class XXXController implements Controller {
@Override
public String handlerRequest(HttpServletRequest request,HttpServletResponse response) {
String op = request.getParameter("op");
//以add方法作为实例
if("add".equals(op)){
//TODO:从前端获取参数getParameter();
ApplicationContext ac = WebApplicationContextUtils.findWebApplicationContext(request.getServletContext());
//TODO:Service部分
return "show.jsp";
}
return null;
}
三,DispatcherServlet
1,接收用户请求解析给拦截器controller然后传给服务层(service层)
2,拦截器接收服务层处理的结果传给DispatcherServlet,解析uri地址<controller中的return ...>
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.解析地址: http://localhost:8080/testSpringmvc_copy/xxx.action
String uri = request.getRequestURI();
//2.取出xxx.action==>xxx
String actionName = uri.substring( uri.lastIndexOf("/")+1); //xxx.action
String cotrollerName = actionName.substring(0,actionName.lastIndexOf("."));
//3.根据请求的参数调对应的XxxController处理器
Controller controller = null;
if("Xxx".equals(cotrollerName)){
controller = new XxxController();
}
//4.调用controller中的handlerRequest()方法处理
String dispatcherUrl = null;
if(controller!=null){
dispatcherUrl = controller.handlerRequest(request, response); //获取handlerRequest()返回值
}
//5.获取返回值
if(dispatcherUrl!=null){
//6.跳转页面
request.getRequestDispatcher(dispatcherUrl).forward(request, response);
}else{
request.getRequestDispatcher("404.jsp").forward(request, response);
}
问题一:
写到这里,因为一个项目中不可能只有一个实体操作,也就是说有多少个实体对象就要创建多少个拦截器实例(Xxxcontroller),那么在这里的逻辑中每一次都要经过一次if...else if...语句的层层筛选,所以为了避免如此,思考是否可以利用Spring的IOC机制,就像配置实体类那样来配置controller然后由spring生成实例对象,然后我们直接取呢?
<!-- 配置controller -->
<bean name="xxxController" class="com.yc.servlet.XxxController"></bean>
配置之后用注解的方式修改代码给值,然后修改上面的判断语句
ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
Controller controller = (Controller) ac.getBean("xxxController");
测试之后发现可用,这样就有效的减少了不必要判断语句的书写
利用Spring的IOC机制,管理好处理器之后,问题又来了,配置之后到底使用多例还是单例呢?
想想servlet----->多例----------->对于拦截器而言,就是处理来自DispatcherServlet的处理请求,然后返回处理后的结果给DispatcherServlet。所以使用多例。
问题二:在模型和视图中建立一种联系,是否可以用模型取得参数?是否一定就需要用转发?一定需要一个String的返回值类型吗?
四,建立模型,获取参数与跳转方式
1.以前J2ee部分取得参数,根据参数名取request.getParameter(); 可以看成是一个Map类型 (参数名 , 参数值)
private Map<String,String> parameterMap = new HashMap<String,String>();
public Map<String, String> getParameterMap() {
return parameterMap;
}
public void setParameterMap(Map<String, String> parameterMap) {
this.parameterMap = parameterMap;
}
因为依赖于web,实际上还是用request来取得参数,但是包装到了Map中,然后通过模型建立的联系来操作
2.在模型与显示界面之间的request,session,application请求,重定向与转发跳转的模拟
public static final String WEBSCOPE_REQUEST="request";
public static final String WEBSCOPE_SESSION ="session";
public static final String WEBSCOPE_APPLICATION ="application";
private String uri; //跳转地址
private boolean isDirect; //如何跳转 true重定向 false转发
private Object model; //模型 用于在uri界面显示的模型
private String webScope; //模型保存的作用域
3.在拦截器controller接口中创建建立模型处理获取参数与跳转的方法
/**
* 处理器中处理参数获取与跳转
* @param model
* @return
*/
public ModelAndView handlerRequest(Model model);
4.修改DispatcherServlet中跳转的代码
思路:得到请求的类型 ---》得到跳转的方式
获得请求的类型:
ModelAndView mv =null;
if(controller!=null){
/* dispatcherUrl = controller.handlerRequest(request, response); 获取handlerRequest()返回值 return "...";
*/ Model model = new Model();
mv = controller.handlerRequest(model);
}
if(mv==null){
request.getRequestDispatcher("404.jsp").forward(request, response);
}else{
if(mv.getModel()!=null){
switch(mv.getWebScope()){
case ModelAndView.WEBSCOPE_REQUEST:
request.setAttribute(mv.getModelName(), mv.getModel());
break;
case ModelAndView.WEBSCOPE_SESSION:
request.getSession().setAttribute(mv.getModelName(), mv.getModel());
break;
case ModelAndView.WEBSCOPE_APPLICATION:
request.getServletContext().setAttribute(mv.getModelName(), mv.getModel());
break;
}
}
获得跳转的方式:
if(mv.getUri()!=null){
if(mv.isDirect()){
response.sendRedirect(mv.getUri());
}else{
request.getRequestDispatcher(mv.getUri()).forward(request, response);
}
}
测试:
总结SpringMvc底层: 用户请求-->DispatcherServlet-->拦截器实例(实现拦截器接口) -->通过实现拦截器接口的方法把请求传给服务层(service层)-->调用Dao层方法-->回传参数给拦截器实例-->拦截器实例接收回传给DispatcherServlet-->解析调jsp页面