需求分析
1、博客列表页
博客列表页能够展示当前的博客列表,每一篇博客展示标题,发布时间、摘要。点击标题可以跳转至正文页
2、博客正文页
显示博客详细内容,标题、发布时间、作者、正文
3、博客编辑页
显示一个编辑框,用户可以编辑博客内容并提交给服务器
4、删除博客功能
5、注册登陆功能
登陆成功,才可以对博客进行相关操作,没登陆只能查看
数据库设计
使用数据库存储博客信息,先进行数据库设计,再开发博客列表页,进行数据库设计,重点就是分析出当前需要几张表,以及每个表中有那些字段,这些字段之间的关系等
一般会把建库建表的代码放到一个专属文件里,方便后续随时创建这样的表结构
表1:博客表
blogId 博客id
title 标题
content 正文
postTime 发布时间
userId 作者id
表2:用户表
userId 用户id
username 用户名
password 密码
封装数据库
把JDBC操作数据库的代码进行封装
先封装与数据库建立连接的过程,使用 单例 类封装数据库建立连接的过程
getDataSource()
这个方法用来查看当前是否有datasource,如果有的话,就直接返回当前datasource,如果没有,就创建一个datasource进行返回
public class DBUtil {
private static final String url = "jdbc:mysql://localhost:3306/SNote?characterEncoding=UTF-8&useSSL=false";
private static final String username = "";//此处填写访问数据库的用户名及密码
private static final String password = "";
private static DataSource dataSource = null;
public static DataSource getDataSource(){
if (dataSource == null){
dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl(url);
((MysqlDataSource)dataSource).setUser(username);
((MysqlDataSource)dataSource).setPassword(password);
}
return dataSource;
}
public static Connection getConnection(){
try {
return getDataSource().getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void close(Connection connection , PreparedStatement preparedStatement , ResultSet resultSet){
try {
if (resultSet != null){
resultSet.close();
}
if (preparedStatement != null){
preparedStatement.close();
}
if (connection != null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
创建实体类
创建实体类,此处就需要两个实体类,一个用户,一个博客
博客类
public class Blog {
private int bolgid;
private String title;
private String content;
private int userId;
private Timestamp postTime;
public int getBolgid() {
return bolgid;
}
public void setBolgid(int bolgid) {
this.bolgid = bolgid;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public Timestamp getPostTime() {
return postTime;
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
@Override
public String toString() {
return "Blog{" +
"bolgid=" + bolgid +
", title='" + title + '\'' +
", content='" + content + '\'' +
", userId=" + userId +
", postTime=" + postTime +
'}';
}
}
用户类
public class User {
private int userId;
private String username;
private String password;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
Dao层
根据需求分析对数据库进行相关操作,也就是创建DAO类
DAO data access object 意为通过这样的类,来操作或访问对应的对象
博客:BlogDao:
public class BlogDao {
public void insert(Blog blog){
Connection con = DBUtil.getConnection();
String sql = "insert into blog values (null,?,?,?,now())";
PreparedStatement pre = null;
try {
pre = con.prepareStatement(sql);
pre.setString(1,blog.getTitle());
pre.setString(2,blog.getContent());
pre.setInt(3,blog.getUserId());
pre.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(con,pre,null);
}
}
public void delete(int blogId){
Connection con = DBUtil.getConnection();
String sql = "delete from blog where blogId = ?";
PreparedStatement pre = null;
try {
pre = con.prepareStatement(sql);
pre.setInt(1,blogId);
pre.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(con,pre,null);
}
}
public List<Blog> selectAll(){
List<Blog> blogs = new ArrayList<>();
Connection con = DBUtil.getConnection();
String sql = "select * from blog";
PreparedStatement pre = null;
ResultSet ret = null;
try {
pre = con.prepareStatement(sql);
ret = pre.executeQuery();
while (ret.next()){
Blog blog = new Blog();
blog.setBolgid(ret.getInt("blogId"));
blog.setTitle(ret.getString("title"));
blog.setContent(ret.getString("content"));
blog.setUserId(ret.getInt("userId"));
blog.setPostTime(ret.getTimestamp("postTime"));
blogs.add(blog);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(con,pre,ret);
}
return blogs;
}
public Blog select(int blogId){
Connection con = DBUtil.getConnection();
String sql = "select * from blog where blogId = ?";
PreparedStatement pre = null;
ResultSet ret = null;
try {
pre = con.prepareStatement(sql);
pre.setInt(1,blogId);
ret = pre.executeQuery();
if (ret.next()){
Blog blog = new Blog();
blog.setBolgid(blogId);
blog.setTitle(ret.getString("title"));
blog.setContent(ret.getString("content"));
blog.setUserId(ret.getInt("userId"));
blog.setPostTime(ret.getTimestamp("postTime"));
return blog;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(con,pre,ret);
}
return null;
}
}
用户:UserDao
public class UserDao {
public void insert(User user){
Connection con = DBUtil.getConnection();
String sql = "insert into user values (null,?,?)";
PreparedStatement pre = null;
try {
pre = con.prepareStatement(sql);
pre.setString(1,user.getUsername());
pre.setString(2,user.getPassword());
pre.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(con,pre,null);
}
}
public User selectByName(String username){
Connection con = DBUtil.getConnection();
String sql = "select * from user where username = ?";
PreparedStatement pre = null;
ResultSet ret = null;
try {
pre = con.prepareStatement(sql);
pre.setString(1,username);
ret = pre.executeQuery();
while (ret.next()){
User user = new User();
user.setUserId(ret.getInt("userId"));
user.setUsername(ret.getString("username"));
user.setPassword(ret.getString("password"));
return user;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(con,pre,ret);
}
return null;
}
public User findById(int userId){
Connection con = DBUtil.getConnection();
String sql = "select * from user where userId = ?";
PreparedStatement pre = null;
ResultSet ret = null;
try {
pre = con.prepareStatement(sql);
pre.setInt(1,userId);
ret = pre.executeQuery();
while (ret.next()){
User user = new User();
user.setUserId(ret.getInt("userId"));
user.setUsername(ret.getString("username"));
user.setPassword(ret.getString("password"));
return user;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(con,pre,ret);
}
return null;
}
}
实现页面
博客列表页面
查看当前系统中存了哪些博客
@WebServlet("/bloglist")
public class BlogListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BlogDao blogDao = new BlogDao();
List<Blog> blogs = blogDao.selectAll();
StringBuilder html = new StringBuilder();
for (Blog blog: blogs){
html.append("<div>");
html.append(String.format("<a href = \"%s\">%s</a>","blogContent?blogId="+blog.getBolgid(),blog.getTitle()));
html.append(String.format("<div>%s</div>",blog.getPostTime()));
html.append(String.format("<div>%s</div>",blog.getContent().substring(0,100)+"..."));
html.append("</div>");
}
resp.setContentType("text/html;charset = utf-8");
resp.getWriter().write(html.toString());
}
}
这个动态页面是通过代码来生成的,但是用字符串拼接的方式来构造HTML是非常麻烦的,麻烦的主要原因就是当HTML比较复杂的时候,代码就会变得很混乱,而且极难去排查错误,更推荐使用模板来代替原始的字符串拼接,所谓的模板就是一个不完整的HTML文件,这个文件关于关键的信息是不全的,我们可以根据服务器这边的数据,把这个不完整的HTML文件补全,最终形成一个完整的HTML文件,再把这个HTML文件返回给浏览器即可。这样一来,我们的工作量就会少很多
在JAVA中,操作模板有很多现成的库,本项目主要使用Thymeleaf库来完成模板的渲染工作
如果这个渲染工作是在服务器这边完成的,就叫做服务器渲染,在客户端完成的,就叫做客户端渲染
既然用了Thymeleaf,就需要在代码中对Thymeleaf进行初始化。
创建一个engine对象 模板引擎 负责把java中的数据替换到模板中
创建一个resolver对象 解析器 负责找到html模板在哪,并加载到内存中供engine来使用
给resolver设置一些属性,让resolver可以找到模板在哪。首先设置字符集,prefix表示前缀,设定了满足什么条件的文件被加载到内存中做为html模板(也就是目录,从webapp这一层开始算。)、Suffix表示后缀,与前缀意思基本相同
把engine和resolver关联起来
初始化完毕后,就可以使用Thymeleaf来进行渲染了
渲染的时候需要定义一个 数据集合WebContext 的概念 ,WebContext的功能就是把需要替换的数据给收集起来,统一的传给模板引擎
@WebServlet("/bloglist")
public class BlogListServlet extends HttpServlet {
TemplateEngine engine = new TemplateEngine();
@Override
public void init() throws ServletException {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
resolver.setCharacterEncoding("utf-8");
resolver.setPrefix("WEB-ING/template/");
resolver.setSuffix(".html");
engine.setTemplateResolver(resolver);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BlogDao blogDao = new BlogDao();
List<Blog> blogs = blogDao.selectAll();
WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("blogs",blogs);
String html = engine.process("blog_list",webContext)
resp.setContentType("text/html;charset = utf-8");
resp.getWriter().write(html);
}
}
博客展示页
从请求中读取出blogId,根据blogId查询到博客,然后再渲染到模板中
@WebServlet("/blogContent")
public class BlogContentServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset =utf-8");
String blogId = req.getParameter("blogId");
if (blogId == null || "".equals(blogId)){
resp.sendError(404);
return;
}
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.select(Integer.parseInt(blogId));
if (blog == null){
resp.sendError(404);
return;
}
UserDao userDao = new UserDao();
User user = userDao.findById(blog.getUserId());
if (user == null){
resp.sendError(404);
return;
}
TemplateEngine engine = (TemplateEngine) getServletContext().getAttribute("engine");
WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("blog",blog);
webContext.setVariable("user",user);
String html = engine.process("blog_content", webContext);
resp.getWriter().write(html);
}
}
博客展示页面:
<!doctype html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>博客内容页</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
background-color: #f3f3f3;
}
.container{
width: 1100px;
margin: 0 auto;
background-color: #fff;
}
h3{
text-align: center;
font-size: 36px;
padding: 10px 0;
}
.post-time{
text-align: center;
color: #9f9f9f;
}
.author{
text-align: center;
padding: 10px 0;
color: #9f9f9f;
}
.content{
padding-bottom: 10px;
text-indent: 40px;
}
</style>
</head>
<body>
<div class="container">
<h3 th:text="${blog.title}">标题</h3>
<div class="author" th:text="${user.username}">作者</div>
<div class="post-time" th:text="${blog.postTime}">2020-02-02 11:11:11</div>
<div class="content" th:text="${blog.content}">正文</div>
</div>
</body>
</html>
登陆页面
登陆:
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
if (username==null||password==null||"".equals(username)||"".equals(password)){
resp.sendError(404,"用户名和密码不能为空!!");
return;
}
UserDao userDao = new UserDao();
User user = userDao.selectByName(username);
if (user == null){
resp.sendError(404,"用户名和密码错误!!");
return;
}
if (!user.getPassword().equals(password)){
resp.sendError(404,"用户名和密码错误!!");
return;
}
HttpSession session = req.getSession(true);
session.setAttribute("user",user);
resp.sendRedirect("bloglist");
}
}
登陆页面:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>用户登录</title>
<style>
*{
margin: 0;
padding: 0;
}
html,
body{
height: 100%;
}
.container{
width: 800px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
height: 80%;
}
input{
display: block;
margin-bottom: 10px;
width: 300px;
height: 30px;
font-size: 20px;
text-indent: 10px;
}
.button{
color: gainsboro;
background-color: cornflowerblue;
border: none;
border-radius: 5px;
}
h3{
padding: 20px;
font-size: 30px;
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<form action="login" method="post">
<h3>登录</h3>
用户名: <input type="text" name="username">
密码: <input type="password" name="password">
<input type="submit" name="登陆" class="button">
</form>
</div>
</body>
</html>
导航栏
实现了登陆页面后,跳转至博客列表页,但是用户没办法确定自己是否登陆,所以可以做一个导航栏,如果没登陆,就显示登陆/注册,如果已经登陆,就显示欢迎xxx
在博客列表页添加:
<div class="nav">
<h2>LIT</h2>
<div class="spacer"></div>
<a href="login.html" class="navb" th:if="${!isLogin}">登陆</a>
<div th:if="${!isLogin}">/</div>
<a href="register.html" class="navb" th:if="${!isLogin}">注册</a>
<div th:if="${isLogin}" th:text="${'欢迎您,' + user.username}"></div>
</div>
style属性里添加
.nav{
height: 30px;
background-color: aquamarine;
color: #9f9f9f;
display: flex;
align-items: center;
}
.navb{
color: black;
}
.spacer{
width: 85%;
}
h2{
padding-left: 20px;
}
当前用户是否登陆,需要在博客列表Servlet代码中进行验证
HttpSession session = req.getSession(false);
boolean isLogin = false;
User user = null;
if (session != null){
user = (User) session.getAttribute("user");
if (user != null){
isLogin = true;
}
}
webContext.setVariable("isLogin",isLogin);
webContext.setVariable("user",user);
注销
在导航栏应有注销字样,实现注销服务:
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(false);
if (session == null){
resp.sendError(404,"当前尚未登陆");
return;
}
session.removeAttribute("user");
resp.sendRedirect("bloglist");
}
}
在博客列表页面中添加:
<a href="logout" class="navb" th:if="${isLogin}">注销</a>
注册页面
页面:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>用户注册</title>
<style>
*{
margin: 0;
padding: 0;
}
html,
body{
height: 100%;
}
.container{
width: 800px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
height: 80%;
}
input{
display: block;
margin-bottom: 10px;
width: 300px;
height: 30px;
font-size: 20px;
text-indent: 10px;
}
.button{
color: gainsboro;
background-color: cornflowerblue;
border: none;
border-radius: 5px;
}
h3{
padding: 20px;
font-size: 30px;
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<form action="register" method="post">
<h3>注册</h3>
用户名: <input type="text" name="username">
密码: <input type="password" name="password">
<input type="submit" name="注册" class="button" value="注册">
</form>
</div>
</body>
</html>
Servlet类:
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
if (username == null || password == null || "".equals(username) || "".equals(password) ){
resp.sendError(404,"用户名或密码为空");
return;
}
UserDao userDao = new UserDao();
User user = userDao.selectByName(username);
if (user != null){
resp.sendError(404,"用户名已存在!!");
return;
}
user = new User();
user.setPassword(password);
user.setUsername(username);
userDao.insert(user);
resp.sendRedirect("login.html");
}
}
博客编辑页
这个页面包含两个输入框,一个文章标题,一个文章内容
还有一个提交按钮,点击就可以给服务器发送请求
实现一个Servlet类来处理这个请求
处理请求前先判定用户是否登陆,如果未登录,则不能正常提交
页面:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>博客编辑页</title>
<style>
*{
margin: 0;
padding: 0;
}
.title{
display: block;
width: 94.8%;
height: 30px;
margin: 10px auto;
font-size: 20px;
text-indent: 10px;
}
textarea{
display: block;
width: 95%;
height: 550px;
margin: 10px auto;
font-size: 20px;
padding: 5px;
box-sizing: border-box;
}
.button{
display: block;
width: 80px;
height: 24px;
margin-left: 50px;
}
h2{
margin: 5px;
text-align: center;
}
h3{
text-indent: 30px;
}
</style>
</head>
<body>
<form action="blogedit" method="post">
<h2>博客编辑页</h2>
<h3>标题:</h3>
<input type="text" name="title" class="title">
<h3>正文:</h3>
<textarea name="content" ></textarea>
<input type="submit" value="发布" class="button">
</form>
</body>
</html>
Servlet类:
@WebServlet("/blogedit")
public class BlogEditServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String title = req.getParameter("title");
String content = req.getParameter("content");
if (title == null || "".equals(title) || content == null || "".equals(content) ){
resp.sendError(404,"标题或内容为空!!");
return;
}
HttpSession session = req.getSession(false);
if (session == null){
resp.sendError(404,"当前尚未登陆");
return;
}
User user = (User) session.getAttribute("user");
if (user == null){
resp.sendError(404,"当前尚未登陆");
return;
}
Blog blog = new Blog();
blog.setTitle(title);
blog.setContent(content);
blog.setUserId(user.getUserId());
BlogDao blogDao = new BlogDao();
blog = blogDao.selectOne(user.getUserId());
resp.sendRedirect("blogContent?blogId=" + blog.getBlogId());
}
}
导航栏添加写博客按钮
<a href="blog_edit.html" class="navb" th:if="${isLogin}">写博客</a>
删除博客
删除功能主要实现在博客详情页,删除时需要验证用户身份是否和博客发布人相同(只能删除自己发布的博客)
删除功能:
添加至博客详情页:
补充
Thymeleaf用法
首先通过Maven 引入Thymeleaf依赖
实现一个模板文件,也就是不完整的HTML文件,这个文件并不是空出一些信息,而是用Thymeleaf特定的特殊符号进行占位,后面就可以借助Thymeleaf库,从而把获取到的信息填入html文件里
模板如下:
<!doctype html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>博客列表页</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
background-color: #f3f3f3;
}
.container{
width: 1100px;
margin: 0 auto;
background-color: #fff;
}
.title{
display: block;
text-align: center;
color: black;
font-size: 20px;
font-weight: 600;
text-decoration: none;
padding: 10px 0;
}
.post-time{
text-align: center;
color: #9f9f9f;
}
.desc{
padding-bottom: 10px;
text-indent: 40px;
}
</style>
</head>
<body>
<div class="container">
<div class="blog" th:each = "blog : ${blogs}">
<a th:href="${'blogContent?blogId='+blog.blogId}" class="title" th:text="${blog.title}">标题</a>
<div class="post-time" th:text="${blog.postTime}">2020-02-02 20:20:20</div>
<div class="desc" th:text="${blog.content}">正文</div>
</div>
</div>
</body>
</html>
th:each = "blog : ${blogs}"
:这是Thymeleaf提供的语法,Thymeleaf中的特殊符号都是由th:开头的,each就表示循环,blog就表示循环中的循环变量,${blogs}
就是一个可迭代对象,此处的blogs就是从数据库查找出来后替换到这里的,每次迭代都会取出一个blog,同时创建出一个class为blog的同级div标签(结构相同)
th:text="${blog.title}"
:th:text就会把变量中的内容按照字符串的方式替换至标签内。
Thymeleaf在替换时首先会判定这个字段是不是public,如果是,就直接取,如果不是,就查看是否存在当前字段的getter方法,如果有,就取出来,如果没有,就报错
通过Thymeleaf在JAVA代码中渲染模板,也称为 服务器渲染
由于初始化Thymeleaf只需要运行一次,而不是每次http请求都要初始化,所以就可以把初始化的代码放入init
但是放入某个init中后,其它Servlet类就不可以使用了,此时就可以使用ServletContext
我们可以把初始化engine的工作交给ServletContext,也可以把engine实例交给ServletContext管理,这样一来,任意Servlet类中都可以都可以拿到ServletContext对象,也就可以拿到engine对象了
借助ServletContext来初始化engine,希望通过ServletContext持有engine引用,进一步的再其它Servlet中获取到这个引用
@WebListener
public class ThymeleafConfig implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
TemplateEngine engine = new TemplateEngine();
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(sce.getServletContext());
resolver.setCharacterEncoding("utf-8");
resolver.setPrefix("WEB-INF/template/");
resolver.setSuffix(".html");
engine.setTemplateResolver(resolver);
ServletContext context = sce.getServletContext();
context.setAttribute("engine",engine);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
如果在Servlet类中需要使用engine,那么就可以通过ServletContext中获取,如下:
TemplateEngine engine = (TemplateEngine) getServletContext().getAttribute("engine");
在代码中,异常处理是很常用的
使用if考虑出错情况和捕获异常都可以处理异常,if:先考虑出错i的情况,最后再执行正确的逻辑,捕获异常是,先执行逻辑,出错了再处理。
web程序中,从收到请求到返回响应,这个过程是期望尽可能快的,而数据库操作是相对比较慢的。如果在处理一个请求时,进行了大量的数据库操作,就可能导致相应返回的太慢,浏览器就等待超时了。
浏览器超时时,用户看到的页面就是404