话说:
亲们,晚上好!正是前面一系列的优化,才有了今天这篇总结。如果读者看到这篇,觉得无厘头,请一定要回头从开始的JDBC系列开始看起,哈哈。
目录
一、BaseServlet的由来
二、多个Servlet合并归一
三、 BaseDao、NewsDao及页面
四、整体总结
整体布局:
一、BaseServlet的由来
为了避免在页面用JSP来处理请求和响应,我们用专业的处理请求和响应的工具——Servlet来替换了doAdd.jsp、doUpdate.jsp等页面。前期由于有多个功能-CURD,每个功能对应一个Servlet,页面虽然减少了,但是Servlet却多了起来。所以,我们就进一步把多个Servlet优化为了一个Servlet,在这个Servlet里面调用方法,然后处理请求,进行响应。这里有两种方式来实现在一个Servlet里面调用不同的方法:一是:采用if() else{}判断页面的请求参数op(operation,我们自己定义的);这个方法的弊端是要判断,而且在判断过后,手动调用,本质也没有优化多少;二是:用类本身创建Method对象,调用invoke()方法来实现方法的自动调用。你传过来的op值是什么,默认就调用和op同名的方法。这就弥补了第一种方法的弊端。
BaseServlet如下:
package com.hmc.jdbc.news.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* User:Meice
* 2017/10/5
*/
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
//根据传递参数决定方法跳转 op代表你访问页面传递的参数operation之含义
String op = req.getParameter("op");
if(op !=null && !"".equals(op)) {
try {
//获取Method对象;这里和我们前面写过的this.getClass().getDeclaredField类似
Method method = this.getClass().getDeclaredMethod(op,HttpServletRequest.class,HttpServletResponse.class);
/**
* 调用invoke()方法;属于java.lang.reflect下面的类
* 自动调用指定的方法 参数1:方法所在的类 参数2:调用方法的参数
*/
//如果不取消访问权限检查,会报IllegalAccessException异常
method.setAccessible(true);
method.invoke(this,req,resp);
} catch (NoSuchMethodException e) {
//这里,我们来掌控,不要让它抛出异常即可。因为不需要携带什么参数,有请重定向上场!但是不利于搞定Bug
e.printStackTrace();
//跳转注意/的区别。/直接从绝对路径开始找,没有了相对路径即当前项目名称了
// resp.sendRedirect("error.jsp");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}else{
System.out.println("参数缺失");
}
}
}
二、多个Servlet合并归一
之所以可以方便的合并为一个Servlet,就是BaseServlet的功劳。我们只用专注的在NewsServlet里面调用各种方法,处理请求和给与响应即可。
NewsServlet中调用了大量BaseDao和NewsDao两个基类中的方法,这两个基类做了漫长的优化之路。这里一并给出,请对比参阅。
NewsServlet
package com.hmc.jdbc.news.servlet;
import com.hmc.jdbc.news.dao.BaseDao;
import com.hmc.jdbc.news.dao.NewsDao;
import com.hmc.jdbc.news.model.News;
import com.hmc.jdbc.news.util.StringConvertUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* User:Meice
* 2017/10/5
*/
@WebServlet(urlPatterns = "/news.do")
public class NewsServlet extends BaseServlet {
NewsDao nd = new NewsDao();
BaseDao bd = new BaseDao();
//查(R)
// 未避免代码混乱,把显示新闻列表封装成方法;这里采用最高级的显示新闻方法listShow3()
private void list (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String sql = "select * from t_news";
List<News> list =(List<News>) bd.listShow3(sql,News.class,null);
//3 存储到req中
req.setAttribute("list", list);
req.getRequestDispatcher("newsShow.jsp").forward(req, resp);
}
//增(C)
private void add(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
//接受参数
String title = req.getParameter("title");
String author = req.getParameter("author");
News news = new News(title,author);
int result = nd.newsAdd2(news);//(写这些方法从后往前写)
if(result > 0) {
req.getRequestDispatcher("news.do?op=list").forward(req,resp);
}else {
req.getRequestDispatcher("newsAdd.jsp").forward(req,resp);
}
}
//改(U)
//显示要修改的新闻
public void changeShow(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
//接受参数
String strId = req.getParameter("id");
int id = StringConvertUtil.getVal(strId);
News news = nd.newsPut3(id);
req.setAttribute("news",news);
req.getRequestDispatcher("newsUpdate.jsp").forward(req,resp);
}
//执行修改操作
public void change(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
//接受参数
String strId = req.getParameter("id");
int id = StringConvertUtil.getVal(strId);
String title = req.getParameter("title");
String author = req.getParameter("author");
News news = new News(id,title,author);
//调用方法
int result = nd.newsUpdate2(news);
if(result >0) {
req.getRequestDispatcher("news.do?op=list").forward(req,resp);
}else {
req.getRequestDispatcher("newsUpdate.jsp").forward(req,resp);
}
}
//删(D)
private void del(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
//接受参数
String strId = req.getParameter("id");
int id = StringConvertUtil.getVal(strId);
int result = nd.newsDel2(id);
req.getRequestDispatcher("news.do?op=list").forward(req,resp);
}
}
三、 BaseDao、NewsDao及页面
BaseDao
package com.hmc.jdbc.news.dao;
import com.hmc.jdbc.news.model.Goods;
import com.hmc.jdbc.news.model.News;
import com.hmc.jdbc.news.model.User;
import com.hmc.jdbc.news.util.ConfigUtil;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
//哎呀,默认导全部的包,如果包到错了怎么办?
public class BaseDao {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
//1、加载驱动,把加载类定义为静态语句块
static {
try {
Class.forName(ConfigUtil.get("driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//说实话感觉卡顿的问题也没怎么解决。可能搜狗输入法还没有和捷克公司做好沟通吧。
}
//2、连接MySQL数据库 定义方法getConn()
public Connection getConn() {
String url = ConfigUtil.get("url");
String user = ConfigUtil.get("user");
String password = ConfigUtil.get("password");
try {
conn = DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.print("恭喜你,连接上了....");
return conn;
}
//3、关闭资源
public void closeJDBC(ResultSet rs, PreparedStatement ps,Connection conn) {
try {
if (rs != null) rs.close();
if (ps != null) ps.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//编写查 把数据库的News输出到控制台
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
BaseDao bd = new BaseDao();
//这里如果赋值,就会报NullPoint错误。
conn = bd.getConn();
try {
//预编译SQL语句
String sql = "select * from t_news";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
//遍历结果集
while(rs.next()){
//这里我们可以分明感受到Idea和Eclipse的差别
int id = rs.getInt(1);
String title = rs.getString("title");
String author = rs.getString("author");
System.out.println(id+"---"+title+"---"+author);
}
} catch (SQLException e) {
e.printStackTrace();
}
new BaseDao().test();
}
/**
* 我们会发现,我们发现,在NewsDao里面,尤其是CUD有大量重复代码,他们结构都差不多,不同的只是Sql语句和SQL带的参数。所以我们可以做如下封装。
*另外,NewsShow中的查询和改(U)代码也几乎完全相同,无非一个是
* select * from t_news ;一个是select * from t_news where id = ? 是否也可以类似CUD那样封装起来?
*
*/
public int CUD(String sql,Object[] params){
int result = 0;
getConn();
try {
ps = conn.prepareStatement(sql);
//问题关键是参数怎么赋值?在参数个数不确定?类型不确定的情况下?
for (int i=0;i<params.length;i++) {
ps.setObject((i+1),params[i]);
}
result = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
closeJDBC(null,ps,conn);
return result;
}
//下面们把查在优化一下
/**
* 这里我们不把SQL写死,我们会在两个地方用到,1是newsShow.jsp用到,
* 另外一个是修改新闻的时候要用到,代码区别仅仅只是SQL语句不同。
*/
public List<News> listShow(String sql, Object[] params) {
List<News> list = new ArrayList<>();
getConn();
try {
ps = conn.prepareStatement(sql);
/**
* 以下方法解决了参数个数和参数类型不同的问题
* 高度抽象,不论你给多少参数,什么类型,都可以处理。
*/
//这里的params可能有,也可以没有比如select * from t_news和select * from t_news where id = ?
//所以最好判断一下
if(params != null && params.length>0) {
for(int i = 0;i<params.length;i++) {
ps.setObject((i+1),params[i]);
}
}
//否则(null),就不用给参数赋值了,直接执行,这样逻辑才够严谨。
rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String title = rs.getString(2);
String author = rs.getString("author");
News news = new News(id,title,author);
list.add(news);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
//再次优化查的方式,把List<E>对象也变得灵活抽象,不写死
public List<?> listShow3(String sql ,Class<?> cls,Object... params) {
//创建集合存放
List<Object> list = new ArrayList<>();
getConn();
try {
//预编译
ps = conn.prepareStatement(sql);
//如果带参,遍历赋值
if(params != null && params.length>0){
for(int i =0;i<params.length;i++) {
ps.setObject((i+1),params[i]);
}
}
//执行SQL
rs = ps.executeQuery();
//获取元数据
ResultSetMetaData rsmd = rs.getMetaData();
//遍历
while (rs.next()) {
/**
* 要解决的问题就在这里
* 我们不知道调用该方法的人会传入什么类?那个类中有什么属性?
* 也同样不知道该用什么类型来接收,也同样没法把属性作为一个对象传递给
* list<E>集合?
*/
//实例化对象
Object obj = cls.newInstance();
//获取列数
int count = rsmd.getColumnCount();
//rs.getObject(这里面的列数通过remd获取);
for(int k=1;k<=count;k++) {
//获取列名
String colName = rsmd.getColumnName(k);
//根据列名获取对象字段
Field f = cls.getDeclaredField(colName);
//给字段赋值;获取列值
Object colVal = rs.getObject(colName);
//给对象赋值
f.setAccessible(true);//取消访问检查
f.set(obj,colVal);
}
list.add(obj);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return list;
}
public void test() {
String sql = "select * from t_goods";
List<Goods> list = (List<Goods>) listShow3(sql, Goods.class,null);
System.out.println(list);
}
}
BaseDao和之前最大的区别就是把查做了进一步优化。现在优化的结果就是listShow3()这个方法。不论你实体类怎么变化,给我三个参数:实体类、SQL语句、查询的参数,就可以完美执行查的操作了,并把查询结果存放到一个List<>,(中间是问号)类型中。便于页面传值。其他无大变化。
这里面最关键的用到了Field类。这个类可以把数据库中的字段反射成JavaBean的属性。因为调用listShow3()方法的时候,不知道你会给什么类,只知道你要在哪张表查询,所以在遍历结果集取值并赋值的过程中,Field类起了关键作用。
实体类News
package com.hmc.jdbc.news.model;
public class News {
private int id;
private String title;
private String author;
public News() {
}
public News(int id, String title, String author) {
this.id = id;
this.title = title;
this.author = author;
}
//没有2个参数的构造方法,我自己就造一个出来;因为增加新闻不需要考虑ID,对于客户来说。
public News(String title, String author) {
this.title = title;
this.author = author;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "News{" +
"id=" + id +
", title='" + title + '\'' +
", author='" + author + '\'' +
'}';
}
}
NewsDao
package com.hmc.jdbc.news.dao;
import com.hmc.jdbc.news.model.News;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* User:Meice
* 2017/10/1
*/
public class NewsDao extends BaseDao{
//这个类里面我们要写CURD啦。
//1 查 R
/**
* 我们要把数据从刚才的控制台输出变为输出到页面,所以需要一个类似容器的东西存放我们的数据
* 这里我们用List集合来存放新闻信息,作为运输工具。把我们的代码运输到JSP页面。
*/
public List<News> list() {
List<News> list = new ArrayList<>();
getConn();
String sql = "select * from t_news";
try {
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt(1);
String title = rs.getString("title");
String author = rs.getString("author");
//每次遍历一次,我们就把一行新闻作为一个对象,这就是JavaBean
News news = new News(id,title,author);
list.add(news);
}
} catch (SQLException e) {
e.printStackTrace();
}
//输出做验证,看以上代码是否正确
// System.out.println(list);
closeJDBC(rs,ps,conn);
return list;
}
public static void main(String[] args) {
NewsDao nd = new NewsDao();
//验证list()方法
// nd.list();
}
//2 增 C
//法1:封装发布新闻的方法
public void newsAdd(News news) {
getConn();
String sql = "insert into t_news (title,author) values (?,?)";
try {
//预编译,步骤类似查 R
ps = conn.prepareStatement(sql);
//这里我们使用?来传递,专业名称忘了
ps.setString(1,news.getTitle());
ps.setString(2,news.getAuthor());
//这里执行和查就不一样了,用的是Update方法
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
closeJDBC(null,ps,conn);
}
//法2:封装发布新闻的方法(前后对比明显吧!)
public int newsAdd2(News news){
String sql = "insert into t_news (title,author) values (?,?)";
Object[] params = {news.getTitle(),news.getAuthor()};
return CUD(sql,params);
}
//3 删 D 法一
public void newsDel(int id) {
getConn();
String sql = "delete from t_news where id = ? ";
System.out.println("进来了");
try {
ps = conn.prepareStatement(sql);
ps.setInt(1,id);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
closeJDBC(null,ps,conn);
}
//删除法二
public int newsDel2(int id) {
String sql = "delete from t_news where id = ?";
Object[] params = {id};
return CUD(sql,params);
}
//4 改 U
//法1:第一步,点击修改链接,我们要能把对应的内容放到对应的位置。
public News newsPut(int id) {
getConn();
News news = null;
String sql = "select * from t_news where id = ?";
try {
ps = conn.prepareStatement(sql);
ps.setInt(1,id);
rs = ps.executeQuery();
while (rs.next()) {
id = rs.getInt(1);
String title = rs.getString(2);
String author = rs.getString(3);
news = new News(id,title,author);
}
} catch (SQLException e) {
e.printStackTrace();
}
closeJDBC(rs,ps,conn);
return news;
}
//法2:封装根据对应ID把新闻放到页面的方法(两方法对比结果鲜明!)
public List<News> newsPut2(int id) {
String sql = "select * from t_news where id = ?";
Object[] params = {id};
return listShow(sql,params);
}
//法3:根据最高级版本的查的的方法listShow3()来根据id获取新闻,直接返回新闻信息,便于获取
public News newsPut3(int id) {
String sql = "select * from t_news where id = ?";
Object[] params = {id};
List<News> list =(List<News>) listShow3(sql,News.class,params);
//判断
if(list != null && list.size()>0) {
return list.get(0);
}else{
return null;
}
}
//执行修改操作 法1:
public void newsUpdate(News news) {
getConn();
String sql = "update t_news set title = ? , author = ? where id = ?";
try {
ps = conn.prepareStatement(sql);
ps.setString(1,news.getTitle());
ps.setString(2,news.getAuthor());
ps.setInt(3,news.getId());
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
closeJDBC(null,ps,conn);
}
//执行修改操作 法2:(没有对比就没有伤害)
public int newsUpdate2(News news) {
String sql = "update t_news set title = ?, author = ? where id = ?";
Object[] params = {news.getTitle(),news.getAuthor(),news.getId()};
return CUD(sql,params);
}
}
这个几乎没有变化,读者如果用心看,可以看到优化升级的痕迹。
页面布局
也是和之前的NewsServlet类似。不过这次3个页面搞定!
新闻列表:newsShow.jsp
<%@ page import="java.util.List" %>
<%@ page import="java.util.Enumeration" %>
<%@ page import="com.hmc.jdbc.news.model.News" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="a" %>
<%--
Created by IntelliJ IDEA.
User: Meice
Date: 2017/10/1
Time: 13:30
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--如果不用jstl,还是采用JSP嵌套获取--%>
<%--
<%
//本来在页面,我们获取list集合非常简单,${}这样就获取了,但是实际过程中,我们在JSP代码中没发做到用这个来获取
List<News> list =(List<News>) request.getAttribute("list");
%>
--%>
<html>
<head>
<title>Meice的新闻列表</title>
</head>
<body>
<h2 align="center">Meice的新闻列表</h2>
<table border="1" align="center" width="80%">
<thead>
<tr>
<th>编号</th>
<th>标题</th>
<th>作者</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<%--${news}--%>
<%--这里传过来就是那幅图的场景;现在的问题是我不知道怎么接收这个传递过来的值,直接用EL取出来的是
个List<News>的集合。这边又没法遍历。??
如果不用JSTL,我们用普通的for each,问题是怎么取出这个值。
--%>
<c:forEach var="news" items="${list}">
<tr>
<td align="center">${news.id}</td>
<td align="center">${news.title}</td>
<td align="center">${news.author}</td>
<td align="center">
<a href="news.do?op=changeShow&id=${news.id}">修改</a>
<a href="news.do?op=del&id=${news.id}" onclick="return confirm('真的忍心删我?')">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
<tfoot></tfoot>
</table>
<a href="newsAdd.jsp">发布新闻</a>
</body>
</html>
发布新闻页面newsAdd.jsp
<%--
Created by IntelliJ IDEA.
User: Meice
Date: 2017/10/1
Time: 15:02
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>发布新闻</title>
</head>
<body>
<form action="news.do" method="post">
<%--传递参数的时候,可以直接传参,也可以用隐藏域--%>
<input type="hidden" name="op" value="add"/>
<table>
<tr>
<td>标题</td>
<td><input type="text" name="title"></td>
</tr>
<tr>
<td>作者</td>
<td><input type="text" name="author"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="发布"></td>
</tr>
</table>
</form>
</body>
</html>
修改新闻页面newsUpdate.jsp
<%@ page import="java.util.List" %>
<%@ page import="com.hmc.jdbc.news.model.News" %>
<%@ page import="java.util.ArrayList" %><%--
User: Meice
Date: 2017/10/1
Time: 18:06
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="news.do" method="post">
<input type="hidden" name="op" value="change"/>
<%--既然form表单的提交方式都为post了,那么在带参就不好,所以用隐藏域来传参--%>
<table>
<%--多个可以遍历,一个元素也可以遍历的。否则又要回归到JSP方法取值了--%>
<tr>
<td>编号</td>
<td><input type="text" name="id" value="${news.id}" disabled="disabled" ></td>
</tr>
<tr>
<td>标题</td>
<td><input type="text" name="title" value="${news.title}"></td>
</tr>
<tr>
<td>作者</td>
<td><input type="text" name="author" value="${news.author}"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="确认修改"></td>
</tr>
</table>
</form>
</body>
</html>
也许你还会问,web.xml配置呢?哈哈,我们全部用了Servlet3.0新特性——注解搞定啦。
这里的web.xml也贴出来,作为纪念,里面的配置已经没有任何实质作用啦。
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--news Add Servlet-->
<servlet>
<servlet-name>newsAdd</servlet-name>
<servlet-class>com.hmc.jdbc.news.servlet.NewsAddServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>newsAdd</servlet-name>
<url-pattern>/newsAdd.do</url-pattern>
</servlet-mapping>
<!--news Show Servlet-->
<servlet>
<servlet-name>newsShow</servlet-name>
<servlet-class>com.hmc.jdbc.news.servlet.NewsShowServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>newsShow</servlet-name>
<url-pattern>/newsShow.do</url-pattern>
</servlet-mapping>
<!-- news Update Servlet-->
<servlet>
<servlet-name>newsUpdate</servlet-name>
<servlet-class>com.hmc.jdbc.news.servlet.NewsUpdateServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>newsUpdate</servlet-name>
<url-pattern>/newsUpdate.do</url-pattern>
</servlet-mapping>
<!--news Update Do Servlet-->
<servlet>
<servlet-name>newsUpdateDo</servlet-name>
<servlet-class>com.hmc.jdbc.news.servlet.NewsUpdateDoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>newsUpdateDo</servlet-name>
<url-pattern>/newsUpdateDo.do</url-pattern>
</servlet-mapping>
<!--news Del Servlet-->
<servlet>
<servlet-name>newsDel</servlet-name>
<servlet-class>com.hmc.jdbc.news.servlet.NewsDelServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>newsDel</servlet-name>
<url-pattern>/newsDel.do</url-pattern>
</servlet-mapping>
<!--news Servlet 这个Servlet可以处理所有操作;只要你给我一个参数-->
<!--用Servlet3.0新特性——注解的时候就可以不用配置啦!-->
<!-- <servlet>
<servlet-name>news</servlet-name>
<servlet-class>com.hmc.jdbc.news.servlet.NewsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>news</servlet-name>
<url-pattern>/news.do</url-pattern>
</servlet-mapping>
-->
<!--错误页面配置-->
<!--<error-page>-->
<!--<!–表示页面错误类型404 400 500之类的–>-->
<!--<error-code>404</error-code>-->
<!--<!–这里配置错误页面位置–>-->
<!--<location>/error.jsp</location>-->
<!--<!–这个配置是配置错误类型类似:NullPointException–>-->
<!--<!–<exception-type></exception-type>–>-->
<!--</error-page>-->
<!--既然是Servlet新特性,我们把Filter也加入进来,这里过滤字符编码;加入注解,也就不用配置了-->
<!-- <filter>
<filter-name>encoding</filter-name>
<filter-class>com.hmc.jdbc.news.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>-->
<!--加入我们的监听器TestHttpSessionListener;这里同样可以加入注解,取消配置-->
<!-- <listener>
<listener-class>com.hmc.jdbc.news.listener.TestHttpSessionListener</listener-class>
</listener>
-->
</web-app>
优化到这里,就会明白一个道理,温故知新,知历史方能更好的知未来。不经历优化的漫长体验,就无法体会优化后的爽歪歪。
四、整体总结
四点总结
1、根据ID获取News对象,封装成方法。这是个很好的优化过程,之前我们每次修改和删除传递ID的时候,都是接收后,然后转换为整型,搞得很无语。现在好了,一个方法,随时调用。当你重复代码多起来的时候,就思考下,怎么来简化。
package com.hmc.jdbc.news.util;
/**
* User:Meice
* 2017/10/8
*/
public class StringConvertUtil {
//还记得每次修改和删除的时候,都要接受字符串id嘛,转换的很辛苦,每次都重复这段代码,今天从根源解决一下
/**
* 1 接受参数
*int id = 0;
*String strId = req.getParameter("id");
*if (strId != null && !"".equals(strId)) {
*id = Integer.valueOf(strId);
*}
*/
//未方便调用,直接来个静态的
public static int getVal(String str){
int id =0;
if(str != null && !"".equals(str)) {
id = Integer.parseInt(str);
}else{
id =0;
}
return id;
}
}
2、 public List<问号> listShow3(String sql ,Class<问号> cls,Object… params) {}
这里List<问号>写?而不写Object大有作用,这里的?代表Object以及任何实体类,
这样在调用该方法的时候,返回值的类型可以强转成任意需要的类型:
List<News> list =(List<News>)
listShow3(sql,News.class,params);
但是,如果方法开始这么定义public List listShow3(String sql ,Class<问号> cls,Object… params){}
那么接收的时候,就无法转换类型。实体类没发强转成List类。
示例:
//以下方法的弊端是:你传过去的是个List里面存放的是 Object的集合,不好取值
/* String sql = "select * from t_news where id = ?";
Object[] params = {id};
//调用这个在查功能上万能的方法,哈哈!
List<Object> list = bd.listShow3(sql,News.class,params);
//传参
req.setAttribute("list",list);
//页面跳转
try {
req.getRequestDispatcher("newsUpdate.jsp").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
*/
你返回的是一个List里面存放的是Object对象,那么我们的JavaBean呢?根本没用上呢
3、传递多个参数,用&连接
<a href="news.do?op=changeShow&id=${news.id}">修改</a>
别写成这样:
<a href="news.do?op=changeShow&?id=${news.id}">修改</a>
4、修改新闻的时候,让新闻编号id显示还是不显示?如何显示,This is a question!
<tr>
<td>编号</td>
<td><input type="text" name="id" value="${news.id}" readonly="readonly"></td>
</tr>
1)编号是后台把控的,如果不想用户看到,可以作为隐藏域
<input type="hidden" name="id" value="${news.id}"/>
这样在form表单提交的时候,id照样可以传过去,便于后台执行修改操作。那为什么不直接在
<form action="news.do" method="post">
里的news.do?id=${news.id}这样带参?又是post提交,又带参,就不好了。
2)除了设置为readonly=”readonly”之外,我们表面上还可以设置为diabled=”disabled”;但是虽然也达到了了用户不能修改id的目的且显示灰色,表示不能修改。但是,一旦改为这个,在点击提交的时候,id就没发传到后台。我们的修改和删除全都依靠id来操作…….
我们在NewsServlet里面接受参数那几行代码设置断点,然后DeBug观察参数变化,如图:
实践是检验真理的唯一标准,果然,后台没有接收到参数id.
所以,慎用disabled属性。
大数据里面,HBase表格中,一张表只有disabled,才能删除。属性之间是相通的。
好了,各位,晚安!下次再会!
本文介绍了一种基于JDBC的Web应用程序优化方案,包括合并多个Servlet为一个BaseServlet、改进BaseDao和NewsDao类以增强代码复用性和灵活性,以及简化页面布局。
662

被折叠的 条评论
为什么被折叠?



