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.png3.2book
44031d95-f8d0-4d72-8eb2-92eb3038071e.png3.3diary
f29b2864-0667-4604-a297-6e86e2920a64.png4.账号
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);
}
网友评论