1.需求
2.maven環(huán)境搭建
http://www.cnblogs.com/wql025/p/5215570.html
2.1.項(xiàng)目結(jié)構(gòu):
如果運(yùn)行時(shí)找不到j(luò)ar包:
http://blog.csdn.net/wf632856695/article/details/53425422
3.數(shù)據(jù)庫(kù)
3.1account
3.2book
3.3diary
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)目地址
5.整個(gè)項(xiàng)目的MVC:
目的是將各個(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)格式
<constant name="struts.ui.theme" value="simple"></constant>
(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;
}
}
@Test
public void test() throws Exception {
IBookDao bookDao = BeanFactory.getBean("bookDao",BookDaoImpl.class);
IAccountDao accountDao = BeanFactory.getBean("bookDao",AccountDaoImpl.class);
}