豆瓣項(xiàng)目

1.需求

2.maven環(huán)境搭建

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

2.1.項(xiàng)目結(jié)構(gòu):

Paste_Image.png

如果運(yùn)行時(shí)找不到j(luò)ar包:
http://blog.csdn.net/wf632856695/article/details/53425422

3.數(shù)據(jù)庫(kù)

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.賬號(hào)

4.1賬戶對(duì)象(Account):

/**
 * 用戶基本信息
 */
@Data
public class Account {
    //唯一編號(hào):
    private Long id;
    // 賬戶名稱:
    private String email;
    //賬戶密碼:
    private String password;
    //賬戶昵稱:
    private String nickName;
    //電話號(hào)碼:
    private String phoneNumber;
    //頭像地址:
    private String iconUrl;
    //個(gè)性簽名:
    private String intro;
    // 注冊(cè)時(shí)間:
    private Date registerTime;
}

4.2業(yè)務(wù)方法:先編寫在DAO組件中:

public interface IAccountDao {

    //保存用戶
    public Boolean save(Account account);

    //修改用戶信息
    public Boolean update(Account account);

    //刪除用戶
    public Boolean delete(Account account);

    //查詢單個(gè)
    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;
    }
}

數(shù)據(jù)庫(kù)操作模板,這里就不貼代碼了,在最后會(huì)有整個(gè)項(xiàng)目地址


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

5.整個(gè)項(xiàng)目的MVC:

j2ee三層架構(gòu).png

目的是將各個(gè)模塊分離,舉個(gè)簡(jiǎn)單的例子:加入持久層從Hibernate轉(zhuǎn)為MyBatis,只需要在Service跟換調(diào)用方式就可以了;

6.Service層

在判斷郵箱是否被注冊(cè)之后,拋出一個(gè)異常。這里自己定義一個(gè)LogicExecption,專門處理業(yè)務(wù)邏輯異常;
在調(diào)用這個(gè)方法時(shí),如果抓取到異常,就不會(huì)往下執(zhí)行;

public class AccountServiceImpl implements IAccountService {


    IAccountDao accountDao = new AccountDaoImpl();


    public Account register(Account account) {
        //根據(jù)郵箱判斷該郵箱是否被注冊(cè),如果被注冊(cè)返回一個(gè)異常
        boolean isExits=accountDao.checkEmila();
        if(isExits){
            throw new LogicExecption("親,該賬戶已經(jīng)被注冊(cè)");
        }
        //對(duì)密碼進(jìn)行加密
        account.setPassword(MD5.encode(account.getPassword()));
        account.setRegisterTime(new Date());
        long id=accountDao.save(account);
        account.setId(id);
        //添加用戶,并返回注冊(cè)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);
    }
}

對(duì)應(yīng)地修改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);
            // 設(shè)置占位參數(shù)
            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.前端

注冊(cè)和登錄

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.創(chuàng)建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;
    }


    //校驗(yàn)注冊(cè)
    public void validateRegister() {
        //郵箱
        if (!ValidateUtil.isEmail(account.getEmail())) {
            super.addFieldError("email", "郵箱格式不正確!");
        }
        //手機(jī)
        if (!ValidateUtil.range(account.getPhoneNumber(), 11, 11) ||
                !ValidateUtil.isDiginit(account.getPhoneNumber())) {
            super.addFieldError("phoneNumber", "手機(jī)號(hào)格式不正確!");
        }
        //密碼
        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,因?yàn)槟J(rèn)的提交是input,但是如果有兩個(gè),就找不到;

<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標(biāo)簽

(1)在jsp中配置標(biāo)簽庫(kù)

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

(2)配置struts.xml的表單默認(rèn)格式


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

(3)使用標(biāo)簽:

<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">賬號(hào)</label>
                    <div class="col-sm-6">
                        <s:textfield name="account.email" value="" id="account_login_account_email"  placeholder="請(qǐng)輸入賬號(hào)" 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="請(qǐng)輸入密碼"></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>還沒有豆瓣賬號(hào)?<a href="/register.jsp">立即注冊(cè)</a></div>
        </div>
    </div>
</div>

注意:cssClass

10.圖書對(duì)象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.圖書的高級(jí)查詢

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;





    //給子類調(diào)用,用來設(shè)置查詢條件
    protected void addQuery(String condition, Object... params) {
        this.conditions.add(condition);
        this.parameters.addAll(Arrays.asList(params));
    }



    //暴露給子類讓子類編寫自身的查詢
    protected void customizedQuery() {
        //do nothing
    }




    //返回拼接好的Sql語(yǔ)句: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;
        }
    }
}

在對(duì)應(yīng)的具體查詢類(繼承QueryObject)中設(shè)置條件參數(shù):重寫父類方法的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.分頁(yè)查詢

對(duì)查詢結(jié)果和分頁(yè)數(shù)據(jù)進(jìn)行封裝:PageResult
提供對(duì)應(yīng)的構(gòu)造參數(shù)

public class PageResult {

    //當(dāng)前頁(yè)的查詢的結(jié)果集:Sql查詢的結(jié)果
    private List<?> listData;
    //符合條件的結(jié)果總數(shù)
    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屬性,以及其對(duì)應(yīng)的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.首頁(yè)顯示

14.我的賬號(hào)

15.文件上傳


 //上傳的文件對(duì)象
    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);
        //存儲(chǔ)頭像地址
        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>

        <!--全局結(jié)果-->
        <global-results>
            <result name="index" type="redirectAction">index</result>
            <result name="register">/register.jsp</result>
            <result name="login">/login.jsp</result>
        </global-results>


        <!--首頁(yè)-->
        <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>


        <!--個(gè)人賬號(hào)-->
        <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.我的分享(分頁(yè)查詢)

17.bean工廠

實(shí)際就是一個(gè)簡(jiǎn)單工廠類,用來創(chuàng)建對(duì)象;

在Dao是實(shí)力創(chuàng)建過程中,我們都是面向接口編程的,對(duì)于具體的實(shí)現(xiàn)是不同的;
但是我們?cè)趧?chuàng)建DAO的對(duì)象時(shí),卻用了實(shí)際的實(shí)現(xiàn)的類。比如:

IAccountDao accountDao = new AccountDaoImpl();


IBookDao bookDao = new BookDaoImpl();

假如有一天要換Dao的實(shí)現(xiàn)類,結(jié)果還需要全部修改調(diào)用的方法,很冗余;
于是創(chuàng)建一個(gè)工廠,專門用來創(chuàng)建我們想要新建的類:
簡(jiǎn)單的模板是:

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");
    }
}

改造升級(jí)之后:

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+"]沒有對(duì)應(yīng)對(duì)象");
        }
        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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容