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,都是之前犯过的错误。所以,伤疤要常揭,揭伤疤不要只是看一看,不要只是同情的看一看,要实在的去重复、重复再重复。


好了,晚安!