美文网首页
豆瓣项目

豆瓣项目

作者: 贾里 | 来源:发表于2017-11-15 21:29 被阅读14次

    1.需求

    2.maven环境搭建

    http://www.cnblogs.com/wql025/p/5215570.html

    2.1.项目结构:

    Paste_Image.png

    如果运行时找不到jar包:
    http://blog.csdn.net/wf632856695/article/details/53425422

    3.数据库

    3.1account

    eba888c0-5bc4-4fb3-9bc1-94d1138aa842.png

    3.2book

    44031d95-f8d0-4d72-8eb2-92eb3038071e.png

    3.3diary

    f29b2864-0667-4604-a297-6e86e2920a64.png

    4.账号

    4.1账户对象(Account):

    /**
     * 用戶基本信息
     */
    @Data
    public class Account {
        //唯一编号:
        private Long id;
        // 账户名称:
        private String email;
        //账户密码:
        private String password;
        //账户昵称:
        private String nickName;
        //电话号码:
        private String phoneNumber;
        //头像地址:
        private String iconUrl;
        //个性签名:
        private String intro;
        // 注册时间:
        private Date registerTime;
    }
    

    4.2业务方法:先编写在DAO组件中:

    public interface IAccountDao {
    
        //保存用户
        public Boolean save(Account account);
    
        //修改用户信息
        public Boolean update(Account account);
    
        //删除用户
        public Boolean delete(Account account);
    
        //查询单个
        public Account get(Long id);
    
        //查询用户列表
        public List<Account> list(int start, int num);
    
    }
    
    public class AccountDaoImpl implements IAccountDao {
        public Boolean save(Account account) {
            String sql = "INSERT INTO account (nickName, password,email,phoneNumber,iconUrl,intro,registerTime) VALUES (?,?,?,?,?,?,?);";
            return JdbcTemplate.update(sql, account.getNickName(), account.getPassword(), account.getEmail(),
                    account.getPhoneNumber(), account.getIconUrl(), account.getIntro(),
                    account.getRegisterTime()) != 0;
        }
    
        public Boolean update(Account account) {
            String sql = "UPDATE account " +
                    "SET nickName = ?," +
                    " password = ?," +
                    " email= ?," +
                    " phoneNumber= ?," +
                    " iconUrl= ?," +
                    " intro= ?," +
                    " registerTime= ? " +
                    "WHERE " +
                    "id = ?;";
            Object[] params = {
                    account.getNickName(),
                    account.getPassword(),
                    account.getEmail(),
                    account.getPhoneNumber(),
                    account.getIconUrl(),
                    account.getIntro(),
                    account.getRegisterTime(),
                    account.getId()
            };
            return JdbcTemplate.update(sql, params) != 0;
        }
    
        public Account get(Long id) {
            String sql = "SELECT * FROM account WHERE id = ?; ";
            Account accounta = (Account) JdbcTemplate.query(sql, new BeanHandler(Account.class), id);
            return accounta;
        }
    
        public List<Account> list(int start, int num) {
            String sql = "SELECT * FROM account LIMIT ?,?";
            Object[] params = {start, num};
            List<Account> accounts = (List<Account>) JdbcTemplate.query(sql, new BeanListHandler(Account.class), params);
            return accounts;
        }
    
    
        public Boolean delete(Account account) {
            String sql = "DELETE FROM account WHERE id = ?";
            return JdbcTemplate.update(sql, account.getId()) != 0;
        }
    }
    

    数据库操作模板,这里就不贴代码了,在最后会有整个项目地址


    fe80bb34-d254-4708-8cb8-f9d1117a0799.png

    5.整个项目的MVC:

    j2ee三层架构.png

    目的是将各个模块分离,举个简单的例子:加入持久层从Hibernate转为MyBatis,只需要在Service跟换调用方式就可以了;

    6.Service层

    在判断邮箱是否被注册之后,抛出一个异常。这里自己定义一个LogicExecption,专门处理业务逻辑异常;
    在调用这个方法时,如果抓取到异常,就不会往下执行;

    public class AccountServiceImpl implements IAccountService {
    
    
        IAccountDao accountDao = new AccountDaoImpl();
    
    
        public Account register(Account account) {
            //根据邮箱判断该邮箱是否被注册,如果被注册返回一个异常
            boolean isExits=accountDao.checkEmila();
            if(isExits){
                throw new LogicExecption("亲,该账户已经被注册");
            }
            //对密码进行加密
            account.setPassword(MD5.encode(account.getPassword()));
            account.setRegisterTime(new Date());
            long id=accountDao.save(account);
            account.setId(id);
            //添加用户,并返回注册id;
            return account;
        }
    
        public Boolean login(Account account) {
            return accountDao.get(account.getId()) != null;
        }
    
    
        public Boolean update(Account account) {
            return accountDao.update(account);
        }
    
        public List<Account> list(int start, int num) {
            return accountDao.list(start, num);
        }
    }
    

    对应地修改jdbc方法,返回主键:

    public static long insert(String sql, Object... params){
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs=null;
            try {
                conn = JdbcUtil.getConn();
                ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                System.out.println("sql:"+sql);
                // 设置占位参数
                for (int i = 0; i < params.length; i++) {
                    ps.setObject(i+1, params[i]);
                }
                ps.executeUpdate();
                rs=ps.getGeneratedKeys();
                if(rs.next()){
                    return rs.getLong(1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JdbcUtil.close(conn, ps, rs);
            }
            return -1L;
        }
    

    7.前端

    注册和登录

    8.搭建struts

    8.1.依赖配置

       <!-- struts2依赖包 -->
            <dependency>
                <groupId>org.apache.struts</groupId>
                <artifactId>struts2-core</artifactId>
                <version>2.3.14</version>
            </dependency>
    

    8.2.配置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">
    
    
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    
    
        <!--struts2-->
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    </web-app>
    

    8.3.创建Action

    public class AccountAction extends ActionSupport {
    
    
        IAccountService accountService = new AccountServiceImpl();
    
        Account account = new Account();
    
    
        public IAccountService getAccountService() {
            return accountService;
        }
    
        public void setAccountService(IAccountService accountService) {
            this.accountService = accountService;
        }
    
        public Account getAccount() {
            return account;
        }
    
        public void setAccount(Account account) {
            this.account = account;
        }
    
    
        //校验注册
        public void validateRegister() {
            //邮箱
            if (!ValidateUtil.isEmail(account.getEmail())) {
                super.addFieldError("email", "邮箱格式不正确!");
            }
            //手机
            if (!ValidateUtil.range(account.getPhoneNumber(), 11, 11) ||
                    !ValidateUtil.isDiginit(account.getPhoneNumber())) {
                super.addFieldError("phoneNumber", "手机号格式不正确!");
            }
            //密码
            if (!ValidateUtil.range(account.getPassword(), 4, 16)) {
                super.addFieldError("password", "密码必须是4-16位!");
            }
            //昵称
            if (!ValidateUtil.hasLength(account.getNickName())) {
                super.addFieldError("nickName", "昵称不能为空!");
            }
            try {
                accountService.register(account);
            } catch (LogicExecption e) {
                super.addFieldError("email", e.getMessage());
            }
    
        }
    
        public String register() {
            System.out.println("register:" + account.toString());
            return NONE;
        }
    
        public void validateLogin() {
            //邮箱
            if (!ValidateUtil.isEmail(account.getEmail())) {
                super.addFieldError("email", "邮箱格式不正确!");
            }
        }
    
    
        @InputConfig(resultName = "login")
        public String login() {
            System.out.println("login:" + account);
            //accountService.login(account);
            return SUCCESS;
        }
    }
    

    8.4.配置struts.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
            "http://struts.apache.org/dtds/struts-2.3.dtd">
    
    <struts>
    
        <constant name="struts.enable.DynamicMethodInvocation" value="false"/>
        <constant name="struts.devMode" value="true"/>
    
    
        <package name="default" extends="struts-default" namespace="/">
            <action name="account_*" class="com.douban.action.AccountAction" method="{1}">
                <result name="index" type="dispatcher">
                    <param name="location">index.jsp</param>
                </result>
    
                <result name="input">/register.jsp</result>
                <result name="login">/login.jsp</result>
            </action>
        </package>
        
    </struts>
    
    

    9.登录

    9.1正常流程

    在action的validateLogin方法中,如果有addFieldError
    需要配置struts中的result,因为默认的提交是input,但是如果有两个,就找不到;

    <result name="input">/register.jsp</result>
    <result name="login">/login.jsp</result>
    

    还需要配置

    @InputConfig(resultName = "login")
        public String login() {
            System.out.println("login:" + account);
            //accountService.login(account);
            return SUCCESS;
        }
    

    struts2标签

    (1)在jsp中配置标签库

    <%@ taglib prefix="s" uri="/struts-tags" %>
    

    (2)配置struts.xml的表单默认格式


    3d693db1-1530-49bb-99ae-7f264c139dec.png
    <constant name="struts.ui.theme" value="simple"></constant>
    
    icon_point.png

    (3)使用标签:

    <div class="container">
        <div class="row">
            <div class="col-xs-4 accont_logo"></div>
        </div>
        <div class="row">
            <div class="col-xs-4 mg-b30"><h3>登录豆瓣</h3></div>
        </div>
        <div class="row">
            <div class="col-xs-6">
                <s:form id="account_login" name="account_login" action="/account_login" method="POST" cssClass="form-horizontal">
                    <div class="form-group">
                        <label for="account.email" class="col-sm-2 control-label">账号</label>
                        <div class="col-sm-6">
                            <s:textfield name="account.email" value="" id="account_login_account_email"  placeholder="请输入账号" cssClass="form-control"></s:textfield>
                        </div>
                        <div class="col-sm-4"></div>
                    </div>
                    <div class="form-group">
                        <label for="account.password" class="col-sm-2 control-label">密码</label>
                        <div class="col-sm-6">
                            <s:password name="account.password" id="account_login_account_password" cssClass="form-control" placeholder="请输入密码"></s:password>
                        </div>
                        <div class="col-sm-4"></div>
                    </div>
    
                    <div class="form-group">
                        <div class="col-sm-offset-2 col-sm-10">
                            <s:submit cssClass="btn btn-success login_btn" value="登录"></s:submit>
                        </div>
                    </div>
                </s:form>
            </div>
            <div class="col-xs-6">
                <div>还没有豆瓣账号?<a href="/register.jsp">立即注册</a></div>
            </div>
        </div>
    </div>
    

    注意:cssClass

    10.图书对象Dao

    public class BookDaoImpl implements IBookDao{
        public long save(Book book) {
            String sql="INSERT INTO book (title,author,isbn,publish,pagecount,price,imgurl,contentabstract,authorabstract,menuabstract,sharerid) " +
                    "VALUES(?,?,?,?,?,?,?,?,?,?,?)";
            Object[] params={book.getTitle(),book.getAuthor(),book.getIsbn(),
                    book.getPublish(),book.getPagecount(),book.getPrice(),book.getImgurl(),
                    book.getContentabstract(),book.getAuthorabstract(),book.getMenuabstract(),
                    book.getSharerid()};
            JdbcTemplate.update(sql,params);
            return 0;
        }
    
        public void update(Book book) {
            String sql="UPDATE book SET title= ?,author=?,isbn=?,publish=?,pagecount=?,price=?,imgurl=?,contentabstract=?,authorabstract=?,menuabstract=?,sharerid=? WHERE id=?;";
            Object[] params={book.getTitle(),book.getAuthor(),book.getIsbn(),
                    book.getPublish(),book.getPagecount(),book.getPrice(),book.getImgurl(),
                    book.getContentabstract(),book.getAuthorabstract(),book.getMenuabstract(),
                    book.getSharerid(),book.getId()};
            JdbcTemplate.update(sql,params);
        }
    
        public void delete(Book book) {
            String sql="DELETE FROM book WHERE id = ?;";
            JdbcTemplate.update(sql,book.getId());
        }
    
        public List<Book> list(int start,int num) {
            String sql="SELECT * FROM  book LIMIT ?, ?";
            return (List<Book>) JdbcTemplate.query(sql, new BeanListHandler(Book.class),start,num);
        }
    
        public Book get(long id) {
            String sql="SELECT * FROM  book WHERE id = ?";
            return (Book) JdbcTemplate.query(sql, new BeanHandler(Book.class),id);
        }
    
        public List<Book> query(ObjectQuery qo) {
            String sql="SELECT * FROM  book"+qo.getQuery();
            Object[] params=qo.getParameters().toArray();
            return (List<Book>) JdbcTemplate.query(sql, new BeanListHandler(Book.class),params);
        }
    }
    

    11.图书的高级查询

    QueryObject:
    主要目的是提供给DAO的查询条件:
    SELECT * FROM xxx +qo.getQuery();

    public class QueryObject {
    
        //查询条件
        private List<String> conditions = new ArrayList<String>();
        //查询条件的占位符
        private List<Object> parameters = new ArrayList<Object>();
        private boolean isBuild = false;
    
    
    
    
    
        //给子类调用,用来设置查询条件
        protected void addQuery(String condition, Object... params) {
            this.conditions.add(condition);
            this.parameters.addAll(Arrays.asList(params));
        }
    
    
    
        //暴露给子类让子类编写自身的查询
        protected void customizedQuery() {
            //do nothing
        }
    
    
    
    
        //返回拼接好的Sql语句:WHERE 条件1 AND 条件2 AND 条件3
        //DAO:SELECT * FROM xxx +qo.getQuery();
        public String getQuery() {
            buildSql();
            if (conditions.isEmpty()) {
                return "";
            }
            StringBuilder sql = new StringBuilder(100).append(" WHERE");
            sql.append(StringUtils.join(conditions, "AND"));
            return sql.toString();
        }
    
    
        public List<Object> getParameters() {
            buildSql();
            return parameters;
        }
    
        private void buildSql() {
            if (!isBuild) {
                this.customizedQuery();
                isBuild = true;
            }
        }
    }
    
    

    在对应的具体查询类(继承QueryObject)中设置条件参数:重写父类方法的customizedQuery
    BookQueryObject:

    public class BookQueryObject extends QueryObject {
    
    
        private String title;
    
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        @Override
        protected void customizedQuery() {
            if(StringUtils.isNotBlank(title)){
                super.addQuery(" title LIKE ? ","%"+title+"%");
            }
        }
    }
    

    12.分页查询

    对查询结果和分页数据进行封装:PageResult
    提供对应的构造参数

    public class PageResult {
    
        //当前页的查询的结果集:Sql查询的结果
        private List<?> listData;
        //符合条件的结果总数
        private int totalCount;
    
    
        private int currentPage=1;
        private int pageSize=5;
    
        private int begin=1;
        private int prev;
        private int next;
        private int total;
    
    
        public PageResult(List<?> listData, int totalCount, int currentPage, int pageSize) {
            this.listData = listData;
            this.totalCount = totalCount;
            this.currentPage = currentPage;
            this.pageSize = pageSize;
            this.total=this.totalCount%this.pageSize==0?this.totalCount/this.pageSize:this.totalCount/this.pageSize+1;
            this.prev=this.currentPage-1>=1?this.currentPage-1:1;
            this.next=this.currentPage+1<=total?this.currentPage+1:total;
    
        }
    
       public static PageResult empty(int pageSize){
            return new PageResult(null,0,1,pageSize);
       }
    
    
        @Override
        public String toString() {
            return "PageResult{" +
                    "listData=" + listData +
                    ", totalCount=" + totalCount +
                    ", currentPage=" + currentPage +
                    ", pageSize=" + pageSize +
                    ", begin=" + begin +
                    ", prev=" + prev +
                    ", next=" + next +
                    ", total=" + total +
                    '}';
        }
    
    
        public List<?> getListData() {
            return listData;
        }
    
        public int getTotalCount() {
            return totalCount;
        }
    }
    

    修改dao的查询方法:

        public PageResult query(QueryObject qo) {
    
            List<Object> params=qo.getParameters();
            int totalCount = JdbcTemplate.query("SELECT COUNT(*) FROM  book" + qo.getQuery(), new IResultSetHandler<Long>() {
    
                public Long handle(ResultSet rs) throws SQLException {
                    if(rs.next()){
                        return rs.getLong(1);
                    }
                    return 0L;
                }
            },params.toArray()).intValue();
            if(totalCount==0){
                 return PageResult.empty(qo.getPageSize());
            }
            params.add((qo.getCurrentPage()-1)*qo.getPageSize());
            params.add(qo.getPageSize());
            String limit=" LIMIT ?,? ";
            String sql="SELECT * FROM  book"+qo.getQuery()+limit;
            List<Book> listData = (List<Book>) JdbcTemplate.query(sql,new BeanListHandler(Book.class),params.toArray());
            return new PageResult(listData,listData.size(),qo.getCurrentPage(),qo.getPageSize());
        }
    

    给QueryObject添加currentPage和pageSize属性,以及其对应的Getter、Setter方法

       private int currentPage=1;
        private int pageSize=5;
        public int getCurrentPage() {
            return currentPage;
        }
    
        public void setCurrentPage(int currentPage) {
            this.currentPage = currentPage;
        }
    
        public int getPageSize() {
            return pageSize;
        }
    
        public void setPageSize(int pageSize) {
            this.pageSize = pageSize;
        }
    

    13.首页显示

    14.我的账号

    15.文件上传

    
     //上传的文件对象
        private File imgUpload;
        //上传的文件名
        private String imgUploadFileName;
    
    
        public String upload() throws Exception {
            String dir = ServletActionContext.getServletContext().getRealPath("/upload");
            String fileName = UUID.randomUUID() + "." + FilenameUtils.getExtension(imgUploadFileName);
            System.out.println("dir:" + dir);
            System.out.println("fileName:" + fileName);
            File uploadFile = new File(dir, fileName);
            FileUtils.copyFile(imgUpload, uploadFile);
            //存储头像地址
            String path = "/upload/" + fileName;
            Account account = getCurrentAccount();
            account.setIconUrl(path);
            accountService.update(account);
            return MYACCOUNT;
        }
    

    16.拦截器

    struts.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
            "http://struts.apache.org/dtds/struts-2.3.dtd">
    
    <struts>
    
        <constant name="struts.enable.DynamicMethodInvocation" value="false"/>
        <constant name="struts.devMode" value="true"/>
        <constant name="struts.ui.theme" value="simple"/>
    
    
        <package name="default" extends="struts-default" namespace="/">
    
            <!--拦截器-->
            <interceptors>
                <interceptor name="loginCheck" class="com.douban.web.intercetpter.LoginIntercepter"/>
            </interceptors>
    
            <!--全局结果-->
            <global-results>
                <result name="index" type="redirectAction">index</result>
                <result name="register">/register.jsp</result>
                <result name="login">/login.jsp</result>
            </global-results>
    
    
            <!--首页-->
            <action name="index" class="com.douban.web.action.IndexAction">
                <result name="index">/index.jsp</result>
            </action>
    
    
            <!--用户-->
            <action name="account_*" class="com.douban.web.action.AccountAction" method="{1}">
                <result type="redirectAction">index</result>
            </action>
    
    
            <!--个人账号-->
            <action name="myaccount_*" class="com.douban.web.action.MyAccountAction" method="{1}">
                <interceptor-ref name="loginCheck"/>
                <interceptor-ref name="defaultStack"/>
                <result>/myAccount.jsp</result>
                <result name="input">/book_input.jsp</result>
                <result name="myaccount" type="redirectAction">myaccount</result>
                <result name="sharebooks" >/mySharedBooks.jsp</result>
            </action>
        </package>
    
    </struts>
    
    

    拦截器

    public class LoginIntercepter extends AbstractInterceptor {
        public String intercept(ActionInvocation actionInvocation) throws Exception {
            Account account = (Account) actionInvocation.getInvocationContext().getSession().get("ACCOUNT_IN_SESSION");
            if (account == null) {
                return "index";
            }
            return actionInvocation.invoke();
        }
    }
    

    18.我的分享(分页查询)

    17.bean工厂

    实际就是一个简单工厂类,用来创建对象;

    在Dao是实力创建过程中,我们都是面向接口编程的,对于具体的实现是不同的;
    但是我们在创建DAO的对象时,却用了实际的实现的类。比如:

    IAccountDao accountDao = new AccountDaoImpl();
    
    
    IBookDao bookDao = new BookDaoImpl();
    

    假如有一天要换Dao的实现类,结果还需要全部修改调用的方法,很冗余;
    于是创建一个工厂,专门用来创建我们想要新建的类:
    简单的模板是:

    public class DaoFactory {
    
    
        public static Object createDao(String name) {
            if (name.equals("bookDao")) {
                return new BookDaoImpl();
            } else if (name.equals("accountDao")) {
                return new AccountDaoImpl();
            }
            return null;
        }
    }
    
    public class FactoryTest {
    
    
        @Test
        public void test1() {
            IBookDao bookDao = (BookDaoImpl) DaoFactory.createDao("bookDao");
            IAccountDao accountDao = (AccountDaoImpl) DaoFactory.createDao("accountDao");
        }
    }
    

    改造升级之后:

    public class BeanFactory {
    
        private static Properties p=new Properties();
        static {
            try {
                p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("dao.properties"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static <T> T getBean(String beanName,Class<T> beanType) throws Exception {
            String className=p.getProperty(beanName);
            if(className==null){
                throw new RuntimeException("该名称["+beanName+"]没有对应对象");
            }
            T obj= (T) Class.forName(className).newInstance();
            if(!beanType.isInstance(obj)){
                throw new RuntimeException("类型不合");
            }
            return obj;
        }
    
    }
    
    fca6aa0b-1795-48bd-9f3c-44c816ff8c08.png
    @Test
        public void test() throws Exception {
            IBookDao bookDao = BeanFactory.getBean("bookDao",BookDaoImpl.class);
            IAccountDao accountDao = BeanFactory.getBean("bookDao",AccountDaoImpl.class);
        }
    

    代码地址:https://git.coding.net/Jack_song/maven_douban.git

    相关文章

      网友评论

          本文标题:豆瓣项目

          本文链接:https://www.haomeiwen.com/subject/dtthmxtx.html