JavaWeb-News-框架前滴最后一次“打怪升级”
来源:互联网 发布:word for mac迅雷下载 编辑:程序博客网 时间:2024/04/29 20:40
话说:
各位读者,下午好!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-News-框架前滴最后一次“打怪升级”
- 联赛前最后一次总结
- LHC升级前最后一波实验
- 我们最后一次晚餐:离婚前,再感动一次
- JavaWeb-Servlet-News(CURD)
- JavaWeb-News-分页
- JavaWeb-News-文件上传
- 打怪升级
- 打怪升级
- 升级打怪
- 打怪升级
- 打怪升级
- 打怪升级
- 打怪升级 CSU
- 打怪升级
- 出嫁前的最后一次人生演习(2)
- 出嫁前的最后一次人生演习(1)
- AMD:DX10.1是DX10的最后一次升级
- scrapy
- Vue 2.0 的 hello world
- 定位算法
- Ubuntu中PyCharm中字体设置
- android微信支付
- JavaWeb-News-框架前滴最后一次“打怪升级”
- Mylistview
- 坚持#第220天~零基础自学云计算基础语言应用41~43节and Shell的1~2节
- P蒜头君当大厨(差分约束)
- 作业三 链栈
- main()程序入口
- Gitbash上传本地代码到github
- logback配置信息英文解释
- spring mvc 出现406错误