话说:
各位读者,下午好!JavaWeb_news前面一直升级,升级到增加了分页和文件上传,今天在写Web框架前做最后一次“打怪升级”,整体原则是把框架底层的一些东西用之前的各种版本串联起来实现,继续实现新闻列表显示。这里主要展现新闻显示,文件上传及分页暂不重复实现。
整体思路是:大体按照MVC设计模式,实现接口编程。增加一个用户登陆判断用户是否存在的功能,但不做细化。有本书《大话设计模式》,蛮好的,不过不是以Java为案例编写的,可以借鉴。
目录
一、整体布局
二、准备工作
三、设计接口
四、实现dao层
五、实现Controler层(Servlet)
六、页面
七、总结
一、整体布局
二、准备工作
1、后台依旧使用news_db数据库和t_news数据表;增加一个数据库
my_news_db和数据表t_user,主要实现后台用户管理。读者可以根据实际情况自行设计。
2、导入的jar包还是和之前一样,导入Tomcat的lib库和jstl-1.2.0.jar
也就是我们的model。
User
package com.hmc.news.model;
/**
* User:Meice
* 2017/10/18
*/
public class User {
private int id;
private String username;
private String password;
public User() {}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public User(String username,String password) {
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
News
package com.hmc.news.model;
/**
* User:Meice
* 2017/10/22
*/
public class News {
private int id;
private String title;
private String author;
private String pic;
public News () {}
public News(int id, String title, String author, String pic) {
this.id = id;
this.title = title;
this.author = author;
this.pic = pic;
}
public News(String title, String author, String pic) {
this.title = title;
this.author = author;
this.pic = pic;
}
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;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
@Override
public String toString() {
return "News{" +
"id=" + id +
", title='" + title + '\'' +
", author='" + author + '\'' +
", pic='" + pic + '\'' +
'}';
}
}
这两个实体类基本无变化。User实现后台用户管理(只有符合条件的用户才能登陆新闻管理界面)
三、设计接口
这次最核心的变化就是实现接口编程。把一些固定的方法抽象成接口,然后用BaseDao和对应的业务类(UserDao、NewsDao)实现。
IUserDao
package com.hmc.news.dao;
import com.hmc.news.model.User;
public interface IUserDao {
//定义获取用户登陆的接口
public User getUser(String username,String password);
}
--------------------------------------------------------------------------------
编写UserDao,实现该接口,对后台是否存在当前用户做一些列业务逻辑判断。如果用户属于管理员,则允许登陆到新闻管理界面,否则就提示无权限。这里不做细化,仅仅只是体现这样一个接口。
IBaseDao
--------------------------------------------------------------------------------
package com.hmc.news.dao;
import java.util.List;
public interface IBaseDao<T> {
//这个接口可以定义很多高层次的抽象
/**
* 根据参数获取对象
* 比如,你给我一个username,password这2个参数,我就能给你返回一个User对象
* 其他对象也是可以的
*/
T getByParam(String sql,Object... objects);
/**
* 获取对象列表
*/
List<T> getList(String sql);
//同样分页也可以这么封装
//Pager<T> getPager(int pageIndex,int pageSize);
//把整个分页作为一个对象传入
//Pager<T> getPager(Pager<T> pager);
/**
* 新增
*/
int add(String sql,Object... objects);
/**
* 修改
*/
int update(String sql,Object... objects);
/**
* 删除
*/
int del(String sql,int id);
}
这个接口高度抽象了我们前面所能想到的所有方法:
查询单个对象、所有对象以及CUD.
INewsDao
package com.hmc.news.dao;
import com.hmc.news.model.News;
public interface INewsDao extends IBaseDao<News> {
}
写好IBaseDao、BaseDao之后,在实现News对象就非常方便了。不论你给我什么对象,我都可以秒秒钟实现CURD.
四、实现dao层
几个Dao层类的顺序是,首先BaseDao==>JdbcDao==>UserDao==>NewsDao
其中JdbcDao和之前升级后的版本一样,BaseDao增加了最为核心的一个方法:获取泛型化参数
BaseDao
package com.hmc.news.dao;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
/**
* User:Meice
* 2017/10/18
*/
public class BaseDao<T> extends JdbcDao implements IBaseDao<T> {
//定义获取泛型化参数的方法getCls()
private Class getCls() {
//获取泛型化父类
Type type =this.getClass().getGenericSuperclass();
System.out.println(type);
//获取泛型化参数类型
ParameterizedType pt = (ParameterizedType)type;
Class cls = (Class)pt.getActualTypeArguments()[0];
return cls;
}
@Override
public T getByParam(String sql,Object... params) {
List<T> list = (List<T>) executeQuery(sql,getCls(),params);
list =(List<T>) executeQuery(sql,getCls(),params);
if(list != null && list.size()>0) {
return list.get(0);
}
return null;
}
@Override
public List<T> getList(String sql) {
List<T> list = (List<T>) executeQuery(sql,getCls(),null);
return list;
}
@Override
public int add(String sql, Object... params) {
return executeCUD(sql,params);
}
@Override
public int update(String sql, Object... params) {
return executeCUD(sql,params);
}
@Override
public int del(String sql, int id) {
return executeCUD(sql,id);
}
}
JdbcDao
package com.hmc.news.dao;
import com.hmc.news.model.News;
import com.hmc.news.util.ConfigUtil;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* User:Meice
* 2017/10/18
*/
public class JdbcDao {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
//定义静态语句块加载JDBC驱动
static{
try {
Class.forName(ConfigUtil.getPro("driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//定义查询对象的方法executeQuery()
public List<?> executeQuery(String sql,Class<?> cls,Object... params) {
//定义一个object类型的集合,用于存放查询的数据
List<Object> list = new ArrayList<>();
conn = getConn();
ps = getPs(sql,params);
//执行查询
try {
rs = ps.executeQuery();
while (rs.next()) {
//解决问题1、如何获取数据库字段名?2、列名和对象属性之间关系如何建立?ResultSetMetaData
//数据表的字段怎么获取呢?就在元表里面。元表怎么知道的呢?因为你给了SQL语句,并且已经执行了,所以可以通过这个接口拿到
ResultSetMetaData rsmd = rs.getMetaData();
//获取有多少字段,便于遍历为每个字段赋值
int count = rsmd.getColumnCount();
//每一行数据就是一个对象
Object obj = cls.newInstance();
//遍历每一行数据(对象)的每个字段,获取列值
for(int i=1;i<=count;i++) {
String colName = rsmd.getColumnName(i);
Object colVal = rs.getObject(colName);
/**
*因为表的列名和类的属性名一致,因此通过反射对象Field
* 设置以后就是为属性赋值了
* Java中数据库表的列名和类的属性就是通过这个反射机制建立起关系的
*/
Field f = cls.getDeclaredField(colName);
/**
* 两个参数
* 第一个:对象
* 第二个:值
* 注意:类的字段一般为private,为避免报错:访问检查,所以设置一下访问权限
*/
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();
} finally {
closeJDBC(rs,ps,conn);
}
return list;
}
//定义查询单个对象的方法executeQueryOne()
public Object executeQueryOne(String sql,Class<?> cls,Object... params) {
conn = getConn();
ps = getPs(sql,params);
//执行查询
try {
rs = ps.executeQuery();
while (rs.next()) {
//解决问题1、如何获取数据库字段名?2、列名和对象属性之间关系如何建立?ResultSetMetaData
//数据表的字段怎么获取呢?就在元表里面。元表怎么知道的呢?因为你给了SQL语句,并且已经执行了,所以可以通过这个接口拿到
ResultSetMetaData rsmd = rs.getMetaData();
//获取有多少字段,便于遍历为每个字段赋值
int count = rsmd.getColumnCount();
//每一行数据就是一个对象
Object obj = cls.newInstance();
//遍历每一行数据(对象)的每个字段,获取列值
for(int i=1;i<=count;i++) {
String colName = rsmd.getColumnName(i);
Object colVal = rs.getObject(colName);
/**
*因为表的列名和类的属性名一致,因此通过反射对象Field
* 设置以后就是为属性赋值了
* Java中数据库表的列名和类的属性就是通过这个反射机制建立起关系的
*/
Field f = cls.getDeclaredField(colName);
/**
* 两个参数
* 第一个:对象
* 第二个:值
* 注意:类的字段一般为private,为避免报错:访问检查,所以设置一下访问权限
*/
f.setAccessible(true);
f.set(obj,colVal);
}
return obj;
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} finally {
closeJDBC(rs,ps,conn);
}
return null;
}
//定义CUD方法(增、改、删)
/**
* 这个方法可以搞定以下形式的CUD操作
* insert into t_news (title,author) values (?,?)
* update t_news set title = ?, author=? where id = ?
* delete from t_news where id = ?
*/
public int executeCUD(String sql,Object... params) {
conn = getConn();
ps = getPs(sql,params);
try {
return ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
closeJDBC(null,ps,conn);
}
return 0;
}
//定义获取连接的方法
/**
* 加载驱动和获取MySQL连接,最开始都是把几个参数写死,后面
*修改外从文件中读取
* 为避免每次获取连接,最好使用数据连接池
*/
public Connection getConn() {
try {
String url = ConfigUtil.getPro("url");
String user =ConfigUtil.getPro("user");
String password = ConfigUtil.getPro("password");
conn = DriverManager.getConnection(url,user,password);
System.out.println("恭喜你,连接上了....");
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
//定义关闭资源方法closeJDBC()
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();
}
}
//定义获取PreparedStatement对象的方法getPs()
/**
*发现,在预编译SQL和为SQL赋值的时候,这部分在executeCUD()和executeQuery()方法里都会用到,
* 所以封装起来,便于调用
*/
public PreparedStatement getPs(String sql,Object... params) {
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]);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return ps;
}
public static void main(String[] args) {
//验证连接MySQL是否成功
JdbcDao jd = new JdbcDao();
String sql = "select * from t_news";
System.out.println(jd.executeQuery(sql, News.class,null));
}
}
UserDao
package com.hmc.news.dao;
import com.hmc.news.model.User;
/**
* User:Meice
* 2017/10/18
*/
public class UserDao extends BaseDao<User> implements IUserDao {
@Override
public User getUser(String username, String password) {
String sql = "select * from t_user where username = ? and password = ?";
Object[] params = {username,password};
User user = getByParam(sql,params);
return user;
}
}
NewsDao
package com.hmc.news.dao;
import com.hmc.news.model.News;
/**
* User:Meice
* 2017/10/22
*/
public class NewsDao extends BaseDao<News> implements INewsDao {
}
NewsDao只需要继承BaseDao,实现接口INewsDao,什么方法也不用写了。这里既可以深刻体会到接口编程的便利!接口编程最核心的就是可扩展性强。
五、实现Controler层(Servlet)
BaseServlet
这个和之前一样,没有变动。最核心的就是Method方法映射,页面请求什么参数,就能主动调用和参数名相同的方法。
package com.hmc.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/16
*/
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
//设置方法映射
String op = req.getParameter("op");
if(op != null && !"".equals(op)) {
try {
Method method = this.getClass().getDeclaredMethod(op,HttpServletRequest.class,HttpServletResponse.class);
method.invoke(this,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}else {
System.out.println("参数缺失....");
}
}
}
NewsServlet
package com.hmc.news.Servlet;
import com.hmc.news.dao.NewsDao;
import com.hmc.news.model.News;
import com.hmc.news.util.StringConvertUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* User:Meice
* 2017/10/22
*/
@WebServlet(urlPatterns = "/news.do")
public class NewsServlet extends BaseServlet{
NewsDao nd = new NewsDao();
//调用显示新闻方法
public void list(HttpServletRequest req,HttpServletResponse resp) {
//直接调用方法
String sql = "select * from t_news";
List<News> list = (List<News>) nd.executeQuery(sql, News.class,null);
req.setAttribute("list",list);
//页面跳转
try {
req.getRequestDispatcher("index.jsp").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void add(HttpServletRequest req,HttpServletResponse resp) {
//接受参数
String title = req.getParameter("title");
String author = req.getParameter("author");
//调用方法
String sql = "insert into t_news (title,author) values (?,?)";
Object[] params = {title,author};
nd.executeCUD(sql,params);
//页面跳转
try {
req.getRequestDispatcher("news.do?op=list").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//定义显示要修改新闻的方法
public void updateShow(HttpServletRequest req,HttpServletResponse resp) {
//接受参数
String strId = req.getParameter("id");
int id = StringConvertUtil.getStr(strId);
//调用方法
String sql = "select * from t_news where id = ?";
Object[] params = {id};
News news = nd.getByParam(sql,params);
//设置参数
req.setAttribute("news",news);
//页面跳转
try {
req.getRequestDispatcher("newsUpdate.jsp").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//定义修改新闻方法update()
public void update(HttpServletRequest req,HttpServletResponse resp) {
//接收参数
String strId = req.getParameter("id");
int id = StringConvertUtil.getStr(strId);
String title = req.getParameter("title");
String author = req.getParameter("author");
//调用方法
String sql = "update t_news set title=?,author=? where id = ?";
Object[] params ={title,author,id};
nd.executeCUD(sql,params);
//页面跳转
try {
req.getRequestDispatcher("news.do?op=list").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void del(HttpServletRequest req,HttpServletResponse resp) {
String strId = req.getParameter("id");
int id = StringConvertUtil.getStr(strId);
String sql = "delete from t_news where id = ?";
Object[] params = {id};
nd.executeCUD(sql,params);
try {
req.getRequestDispatcher("news.do?op=list").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
工具类:ConfigUtil、StringConvertUtil
工具类:ConfigUtil——数据库连接参数
StringConvertUtil——id转换
ConfigUtil
package com.hmc.news.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* User:Meice
* 2017/10/21
*/
//为了更加方便调用,我们把它定义为静态的
public class ConfigUtil {
//定义获取MySQL数据库参数的方法getPro()
public static String getPro(String name) {
Properties pro = new Properties();
//this.getClass().getClassLoader().getResourceAsStream("jdbc.properties");
InputStream is = ConfigUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
pro.load(is);
return pro.getProperty(name);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
//测试getPro()方法
System.out.println(ConfigUtil.getPro("driver"));
}
}
StringConvertUtil
package com.hmc.news.util;
/**
* User:Meice
* 2017/10/22
*/
public class StringConvertUtil {
public static int getStr(String strId) {
int id = 0;
if(strId != null && !"".equals(strId)) {
id = Integer.parseInt(strId);
}else {
id = 0;
}
return id;
}
}
六、页面
页面就不在赘述。
七、总结
一、获取参数化类型,明白list<问号>与List<梯>的区别;
二、面向接口编程
以在下愚见,接口其实就类似战略,高度抽象化,其他的只是实现。面向接口编程,就是要有一种整体化思维,有一种高屋建瓴的思维方式,而不是被细节所吞没。
三、这次重复写了下,出现不少Bug,都是之前犯过的错误。所以,伤疤要常揭,揭伤疤不要只是看一看,不要只是同情的看一看,要实在的去重复、重复再重复。
好了,晚安!
本文介绍了一个基于JavaWeb的新闻管理系统的设计与实现过程,包括整体布局、接口设计、DAO层实现、Controller层(Servlet)编写等内容,并涉及MVC模式的应用。
896

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



