豆瓣项目

1.需求

2.maven环境搭建

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

2.1.项目结构:

豆瓣项目_第1张图片
Paste_Image.png

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

3.数据库

3.1account

豆瓣项目_第2张图片
eba888c0-5bc4-4fb3-9bc1-94d1138aa842.png

3.2book

豆瓣项目_第3张图片
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 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 list(int start, int num) {
        String sql = "SELECT * FROM account LIMIT ?,?";
        Object[] params = {start, num};
        List accounts = (List) 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;
    }
}

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


豆瓣项目_第4张图片
fe80bb34-d254-4708-8cb8-f9d1117a0799.png

5.整个项目的MVC:

豆瓣项目_第5张图片
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 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.依赖配置

   
        
            org.apache.struts
            struts2-core
            2.3.14
        

8.2.配置web.xml





    
        index.jsp
    


    
    
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    

    
        struts2
        /*
    


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






    
    


    
        
            
                index.jsp
            

            /register.jsp
            /login.jsp
        
    
    


9.登录

9.1正常流程

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

/register.jsp
/login.jsp

还需要配置

@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的表单默认格式


豆瓣项目_第6张图片
3d693db1-1530-49bb-99ae-7f264c139dec.png

icon_point.png

(3)使用标签:

登录豆瓣

还没有豆瓣账号?立即注册

注意: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 list(int start,int num) {
        String sql="SELECT * FROM  book LIMIT ?, ?";
        return (List) 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 query(ObjectQuery qo) {
        String sql="SELECT * FROM  book"+qo.getQuery();
        Object[] params=qo.getParameters().toArray();
        return (List) JdbcTemplate.query(sql, new BeanListHandler(Book.class),params);
    }
}

11.图书的高级查询

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

public class QueryObject {

    //查询条件
    private List conditions = new ArrayList();
    //查询条件的占位符
    private List parameters = new ArrayList();
    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 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 params=qo.getParameters();
        int totalCount = JdbcTemplate.query("SELECT COUNT(*) FROM  book" + qo.getQuery(), new IResultSetHandler() {

            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 listData = (List) 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






    
    
    


    

        
        
            
        

        
        
            index
            /register.jsp
            /login.jsp
        


        
        
            /index.jsp
        


        
        
            index
        


        
        
            
            
            /myAccount.jsp
            /book_input.jsp
            myaccount
            /mySharedBooks.jsp
        
    



拦截器

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 getBean(String beanName,Class 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;
    }

}
豆瓣项目_第7张图片
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

你可能感兴趣的:(豆瓣项目)