MVC流程
- MVC , 一种常见的设计方法 。M: Model, 数据; V: View, 显示; C: Controller, 控制。 简单地说,Model负责提供数据,而View负责数据的显示。
例子:以MVC的方式来显示列表数据
列表页模板html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>古诗文网</title>
<link rel="stylesheet" type="text/css" href="./css/common.css"/>
</head>
<body>
<div class="main">
<div>
<p>精选系列</p>
</div>
<#list poem as p>
<div class="item" onclick="window.open('view.do?id=${p.id}','_self')">
${p.title}
</div>
</#list>
</div>
</body>
</html>
后台流程: 新建 IndexPage 类,映射URL为 /index.do ,在doGet() 里,取得数据,存到model里, 将model交付给显示,利用 freemarker,将model里的数据显示在网页中。 至此,Model 和 View 分离。 http://127.0.0.1:8080/demo/index.do
@WebServlet("/index.do")
public class IndexPage extends HttpServlet
{
protected Configuration frmkConfig;
@Override
public void init() throws ServletException
{
// 取得APP所在目录
File appRoot = new File(getServletContext().getRealPath("/"));
try
{
// 初始化FreeMarker ( 模板库 )
frmkConfig = new Configuration(Configuration.VERSION_2_3_28);
frmkConfig.setDirectoryForTemplateLoading(appRoot); // 指定模板根目录
frmkConfig.setDefaultEncoding("UTF-8");
frmkConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
frmkConfig.setLogTemplateExceptions(false);
} catch (Exception e)
{
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Map<String, Object> model = new HashMap<String, Object>();
try (SqlSession sqlSession = db.MyBatis.sqlSessionFactory.openSession())
{
List<Map> rows = sqlSession.selectList("ls.test.getTitleList");
model.put("poem", rows);
}
String view = "index.html";
Template tp = null;
try
{
tp = frmkConfig.getTemplate(view);
} catch (TemplateNotFoundException e)
{
response.sendError(404, "Cannot find view:" + view);
return;
}
// 处理并返回应答
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
Writer writer = response.getWriter();
try
{
tp.process(model, writer);// 输出给客户端
} catch (TemplateException e)
{
e.printStackTrace();
response.sendError(500, e.getMessage());
} finally
{
writer.close();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request, response);
}
}
详情页模板html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${poem.title}-详情</title>
<link rel="stylesheet" type="text/css" href="./css/common.css"/>
</head>
<body>
<div class="main">
<div>标题:${poem.title}</div>
<div>作者:${poem.author}</div>
<div>朝代:${poem.dynasty}</div>
<div>内容:${poem.content}</div>
</div>
</body>
</html>
后台支持 http://127.0.0.1:8080/view.do?id=2
@WebServlet("/view.do")
public class ViewPage extends HttpServlet
{
protected Configuration frmkConfig;
@Override
public void init() throws ServletException
{
// 取得APP所在目录
File appRoot = new File(getServletContext().getRealPath("/"));
try
{
// 初始化FreeMarker ( 模板库 )
frmkConfig = new Configuration(Configuration.VERSION_2_3_28);
frmkConfig.setDirectoryForTemplateLoading(appRoot); // 指定模板根目录
frmkConfig.setDefaultEncoding("UTF-8");
frmkConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
frmkConfig.setLogTemplateExceptions(false);
} catch (Exception e)
{
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
int id = Integer.valueOf(request.getParameter("id"));
Poem poem = null;
Map<String, Object> model = new HashMap<String, Object>();
try (SqlSession sqlSession = db.MyBatis.sqlSessionFactory.openSession())
{
poem = sqlSession.selectOne("ls.test.getContent", id);
model.put("poem", poem);
}
String view = "/view.html";
Template tp = null;
try
{
tp = frmkConfig.getTemplate(view);
} catch (TemplateNotFoundException e)
{
response.sendError(404, "Cannot find view:" + view);
return;
}
// 处理并返回应答
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
Writer writer = response.getWriter();
try
{
tp.process(model, writer);// 输出给客户端
} catch (TemplateException e)
{
e.printStackTrace();
response.sendError(500, e.getMessage());
} finally
{
writer.close();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request, response);
}
}
- 比较 IndexPage 和 ViewPage , 每个 MVC 流程的实现基本相同,除了 view 和 model 还有 url 的不一样。也可以发现,MVC模式下 html 比 REST 好写的多。
MVC与REST对比
REST方式下,请求两次。
MVC方式下请求一次,由后台处理数据、并生成页面返回到浏览器。 浏览器并不知道后台做了这么多事情,在它看来,它只是收到了HTML内容。
MVC与伪静态
- 伪静态:看url像是静态页面,实则由Servlet生成的页面。 做成伪静态页面的目的,一般是为了可以被搜索引擎收录。
使用 MVC 生成伪静态页面 http://127.0.0.1:8080/poem/2.html
比较
http://127.0.0.1:8080/view.do?id=2 之前的代码使用这一种方式,下面我们使用伪静态来实现这个页面,让它看起来像一个静态页面。
@WebServlet("/poem/*")
public class ViewPage2 extends HttpServlet
{
protected Configuration frmkConfig;
@Override
public void init() throws ServletException
{
// 取得APP所在目录
File appRoot = new File(getServletContext().getRealPath("/"));
try
{
// 初始化FreeMarker ( 模板库 )
frmkConfig = new Configuration(Configuration.VERSION_2_3_28);
frmkConfig.setDirectoryForTemplateLoading(appRoot); // 指定模板根目录
frmkConfig.setDefaultEncoding("UTF-8");
frmkConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
frmkConfig.setLogTemplateExceptions(false);
} catch (Exception e)
{
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// int id=Integer.valueOf(request.getParameter("id"));
String contextPath = request.getServletContext().getContextPath();
String requestUri = request.getRequestURI();
String servletPath = requestUri.substring(contextPath.length());
System.out.println("contextPath:" + contextPath);// /demo
System.out.println("requestUri:" + requestUri);// /demo/poem/2.html
System.out.println("servletPath:" + servletPath);// /poem/2.html
// String servletPath2=request.getServletPath();// /poem
int p1 = servletPath.lastIndexOf('/');
int p2 = servletPath.lastIndexOf('.');
int id = Integer.valueOf(servletPath.substring(p1 + 1, p2));
System.out.println("id:" + id);
Poem poem = null;
Map<String, Object> model = new HashMap<String, Object>();
try (SqlSession sqlSession = db.MyBatis.sqlSessionFactory.openSession())
{
poem = sqlSession.selectOne("ls.test.getContent", id);
model.put("poem", poem);
}
String view = "/poem/view.html";
Template tp = null;
try
{
tp = frmkConfig.getTemplate(view);
} catch (TemplateNotFoundException e)
{
response.sendError(404, "Cannot find view:" + view);
return;
}
// 处理并返回应答
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
Writer writer = response.getWriter();
try
{
tp.process(model, writer);// 输出给客户端
} catch (TemplateException e)
{
e.printStackTrace();
response.sendError(500, e.getMessage());
} finally
{
writer.close();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request, response);
}
}
- 小技巧
在伪静态实现里,要注意模板文件的路径,与伪路径要一致。
伪路径:/poem/nnn.html ,模板文件: /poem/view.html 否则,在定义模板时很不方便,相对路径乱套。