文章目录
项目导入
点击按钮将项目导入
选择travel项目的pom.xml文件,点击ok,完成项目导入。需要等待一小会,项目初始化完成。
启动项目
1. 方式1
2. 方式2
技术选型
1. web层
1.1 为什么使用html而不使用jsp?
首先该项目是一个互联网项目,该项目是给普通的用户访问的,所以要追求速度快,而且要做到前后端分离,所以使用html作为视图,如果将来做一些后台管理系统,比如OA和财务管理系统是给内部人员使用的就可以使用jsp作为视图。
- Servlet:前端控制器
- html:视图
- Filter:过滤器
- BeanUtils:数据封装
- Jackson:json序列化工具
2. service层
- Javamail:java发送邮件工具
- Redis:nosql内存数据库
- Jedis:java的redis客户端
3. dao层
- Mysql:数据库
- Druid:数据库连接池
- JdbcTemplate:jdbc的工具
创建数据库
创建数据库
CREATE DATABASE travel;
使用数据库
USE travel;
创建表
复制提供好的sql
工具类
1. JDBCUtils
/*
1. 声明静态数据源成员变量
2. 创建连接池对象
3. 定义公有的得到数据源的方法
4. 定义得到连接对象的方法
5. 定义关闭资源的方法
*/
public class JDBCUtil {
// 1. 声明静态数据源成员变量
private static DataSource ds;
// 2. 创建连接池对象
static {
// 加载配置文件中的数据
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties");
Properties pp = new Properties();
try {
pp.load(is);
// 创建连接池,使用配置文件中的参数
ds = DruidDataSourceFactory.createDataSource(pp);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
// 3. 定义公有的得到数据源的方法
public static DataSource getDataSource() {
return ds;
}
// 4. 定义得到连接对象的方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
// 5.定义关闭资源的方法
public static void close(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
// 6.重载关闭方法
public static void close(Connection conn, Statement stmt) {
close(conn, stmt, null);
}
}
2. JedisUtil
/**
* Jedis工具类
*/
public final class JedisUtil {
private static JedisPool jedisPool;
static {
//读取配置文件
InputStream is = JedisPool.class.getClassLoader().getResourceAsStream("jedis.properties");
//创建Properties对象
Properties pro = new Properties();
//关联文件
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//获取数据,设置到JedisPoolConfig中
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));
//初始化JedisPool
jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port")));
}
/**
* 获取连接方法
*/
public static Jedis getJedis() {
return jedisPool.getResource();
}
/**
* 关闭Jedis
*/
public static void close(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
}
3. MailUtil
/**
* 发邮件工具类
*/
public final class MailUtil {
private static final String USER = "1290089493@qq.com"; // 发件人称号,同邮箱地址
private static final String PASSWORD ="jaitpzdgkrofjgfb"; // 如果是qq邮箱可以使户端授权码,或者登录密码
/**
*
* @param to 收件人邮箱
* @param text 邮件正文
* @param title 标题
*/
/* 发送验证信息的邮件 */
public static boolean sendMail(String to, String text, String title){
try {
final Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.host", "smtp.qq.com");
// 发件人的账号
props.put("mail.user", USER);
//发件人的密码
props.put("mail.password", PASSWORD);
// 构建授权信息,用于进行SMTP进行身份验证
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// 用户名、密码
String userName = props.getProperty("mail.user");
String password = props.getProperty("mail.password");
return new PasswordAuthentication(userName, password);
}
};
// 使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(props, authenticator);
// 创建邮件消息
MimeMessage message = new MimeMessage(mailSession);
// 设置发件人
String username = props.getProperty("mail.user");
InternetAddress form = new InternetAddress(username);
message.setFrom(form);
// 设置收件人
InternetAddress toAddress = new InternetAddress(to);
message.setRecipient(Message.RecipientType.TO, toAddress);
// 设置邮件标题
message.setSubject(title);
// 设置邮件的内容体
message.setContent(text, "text/html;charset=UTF-8");
// 发送邮件
Transport.send(message);
return true;
}catch (Exception e){
e.printStackTrace();
}
return false;
}
public static void main(String[] args) throws Exception {
// 做测试用
MailUtils.sendMail("ginger_mr@163.com","你好,这是一封测试邮件,无需回复。","测试邮件");
System.out.println("发送成功");
}
}
4. Md5Util
/**
* 写一个MD5算法,运行结果与MySQL的md5()函数相同
* 将明文密码转成MD5密码
* 123456->e10adc3949ba59abbe56e057f20f883e
*/
public final class Md5Util {
private Md5Util(){
}
/**
* 将明文密码转成MD5密码
*/
public static String encodeByMd5(String password) throws Exception{
//Java中MessageDigest类封装了MD5和SHA算法,今天我们只要MD5算法
MessageDigest md5 = MessageDigest.getInstance("MD5");
//调用MD5算法,即返回16个byte类型的值
byte[] byteArray = md5.digest(password.getBytes());
//注意:MessageDigest只能将String转成byte[],接下来的事情,由我们程序员来完成
return byteArrayToHexString(byteArray);
}
/**
* 将byte[]转在16进制字符串
*/
private static String byteArrayToHexString(byte[] byteArray) {
StringBuffer sb = new StringBuffer();
//遍历
for(byte b : byteArray){
//16次
//取出每一个byte类型,进行转换
String hex = byteToHexString(b);
//将转换后的值放入StringBuffer中
sb.append(hex);
}
return sb.toString();
}
/**
* 将byte转在16进制字符串
*/
private static String byteToHexString(byte b) {
//-31转成e1,10转成0a,。。。
//将byte类型赋给int类型
int n = b;
//如果n是负数
if(n < 0){
//转正数
//-31的16进制数,等价于求225的16进制数
n = 256 + n;
}
//商(14),数组的下标
int d1 = n / 16;
//余(1),数组的下标
int d2 = n % 16;
//通过下标取值
return hex[d1] + hex[d2];
}
private static String[] hex = {
"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
/**
* 测试
*/
public static void main(String[] args) throws Exception{
String password = "123456";
String passwordMD5 = Md5Util.encodeByMd5(password);
System.out.println(password);
System.out.println(passwordMD5);
}
}
5. UUIDUtil
/**
* 产生UUID随机字符串工具类
*/
public final class UUIDUtil {
private UuidUtil(){
}
public static String getUuid(){
return UUID.randomUUID().toString().replace("-","");
}
/**
* 测试
*/
public static void main(String[] args) {
System.out.println(UuidUtil.getUuid());
System.out.println(UuidUtil.getUuid());
System.out.println(UuidUtil.getUuid());
System.out.println(UuidUtil.getUuid());
}
}
6. druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///travel
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
7. jedis.properties
host=127.0.0.1
port=6379
maxTotal=50
maxIdle=10
实体类
1. Category
/**
* 分类实体类
*/
public class Category implements Serializable {
private int cid;//分类id
private String cname;//分类名称
public Category() {
}
public Category(int cid, String cname) {
this.cid = cid;
this.cname = cname;
}
@Override
public String toString() {
return "Category{" +
"cid=" + cid +
", cname='" + cname + '\'' +
'}';
}
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
}
2. Favorite
/**
* 收藏实体类
*/
public class Favorite implements Serializable {
private Route route;//旅游线路对象
private String date;//收藏时间
private User user;//所属用户
/**
* 无参构造方法
*/
public Favorite() {
}
/**
* 有参构造方法
* @param route
* @param date
* @param user
*/
public Favorite(Route route, String date, User user) {
this.route = route;
this.date = date;
this.user = user;
}
public Route getRoute() {
return route;
}
public void setRoute(Route route) {
this.route = route;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
3. PageBean
/**
* 分页实体类
*/
public class PageBean<T> {
private int currentPage;//当前页
private int currentNumber;//当前页显示的条数
private int totalCount;//总条数
private int totalPage;//总页数
private List<T> list;//每页显示的数据
//添加一个线路名称
private String rname;
public String getRname() {
return rname;
}
public void setRname(String rname) {
this.rname = rname;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getCurrentNumber() {
return currentNumber;
}
public void setCurrentNumber(int currentNumber) {
this.currentNumber = currentNumber;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
@Override
public String toString() {
return "PageBean{" +
"currentPage=" + currentPage +
", currentNumber=" + currentNumber +
", totalCount=" + totalCount +
", totalPage=" + totalPage +
", list=" + list +
'}';
}
}
4. ResultInfo
/**
* 用于封装后端返回前端数据对象
*/
public class ResultInfo implements Serializable {
private boolean flag;//后端返回结果正常为true,发生异常返回false
private Object data;//后端返回结果数据对象
private String errorMsg;//发生异常的错误消息
//无参构造方法
public ResultInfo() {
}
public ResultInfo(boolean flag) {
this.flag = flag;
}
/**
* 有参构造方法
* @param flag
* @param errorMsg
*/
public ResultInfo(boolean flag, String errorMsg) {
this.flag = flag;
this.errorMsg = errorMsg;
}
/**
* 有参构造方法
* @param flag
* @param data
* @param errorMsg
*/
public ResultInfo(boolean flag, Object data, String errorMsg) {
this.flag = flag;
this.data = data;
this.errorMsg = errorMsg;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
5. Route
/**
* 旅游线路商品实体类
*/
public class Route implements Serializable {
private int rid;//线路id,必输
private String rname;//线路名称,必输
private double price;//价格,必输
private String routeIntroduce;//线路介绍
private String rflag; //是否上架,必输,0代表没有上架,1代表是上架
private String rdate; //上架时间
private String isThemeTour;//是否主题旅游,必输,0代表不是,1代表是
private int count;//收藏数量
private int cid;//所属分类,必输
private String rimage;//缩略图
private int sid;//所属商家
private String sourceId;//抓取数据的来源id
private Category category;//所属分类
private Seller seller;//所属商家
private List<RouteImg> routeImgList;//商品详情图片列表
/**
* 无参构造方法
*/
public Route(){
}
/**
* 有参构造方法
* @param rid
* @param rname
* @param price
* @param routeIntroduce
* @param rflag
* @param rdate
* @param isThemeTour
* @param count
* @param cid
* @param rimage
* @param sid
* @param sourceId
*/
public Route(int rid, String rname, double price, String routeIntroduce, String rflag, String rdate, String isThemeTour, int count, int cid, String rimage, int sid, String sourceId) {
this.rid = rid;
this.rname = rname;
this.price = price;
this.routeIntroduce = routeIntroduce;
this.rflag = rflag;
this.rdate = rdate;
this.isThemeTour = isThemeTour;
this.count = count;
this.cid = cid;
this.rimage = rimage;
this.sid = sid;
this.sourceId = sourceId;
}
public List<RouteImg> getRouteImgList() {
return routeImgList;
}
public void setRouteImgList(List<RouteImg> routeImgList) {
this.routeImgList = routeImgList;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public Seller getSeller() {
return seller;
}
public void setSeller(Seller seller) {
this.seller = seller;
}
public String getSourceId() {
return sourceId;
}
public void setSourceId(String sourceId) {
this.sourceId = sourceId;
}
public int getRid() {
return rid;
}
public void setRid(int rid) {
this.rid = rid;
}
public String getRname() {
return rname;
}
public void setRname(String rname) {
this.rname = rname;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getRouteIntroduce() {
return routeIntroduce;
}
public void setRouteIntroduce(String routeIntroduce) {
this.routeIntroduce = routeIntroduce;
}
public String getRflag() {
return rflag;
}
public void setRflag(String rflag) {
this.rflag = rflag;
}
public String getRdate() {
return rdate;
}
public void setRdate(String rdate) {
this.rdate = rdate;
}
public String getIsThemeTour() {
return isThemeTour;
}
public void setIsThemeTour(String isThemeTour) {
this.isThemeTour = isThemeTour;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
public String getRimage() {
return rimage;
}
public void setRimage(String rimage) {
this.rimage = rimage;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
@Override
public String toString() {
return "Route{" +
"rid=" + rid +
", rname='" + rname + '\'' +
", price=" + price +
", routeIntroduce='" + routeIntroduce + '\'' +
", rflag='" + rflag + '\'' +
", rdate='" + rdate + '\'' +
", isThemeTour='" + isThemeTour + '\'' +
", count=" + count +
", cid=" + cid +
", rimage='" + rimage + '\'' +
", sid=" + sid +
", sourceId='" + sourceId + '\'' +
", category=" + category +
", seller=" + seller +
", routeImgList=" + routeImgList +
'}';
}
}
6. RouteImg
/**
* 旅游线路图片实体类
*/
public class RouteImg implements Serializable {
private int rgid;//商品图片id
private int rid;//旅游商品id
private String bigPic;//详情商品大图
private String smallPic;//详情商品小图
/**
* 无参构造方法
*/
public RouteImg() {
}
/**
* 有参构造方法
* @param rgid
* @param rid
* @param bigPic
* @param smallPic
*/
public RouteImg(int rgid, int rid, String bigPic, String smallPic) {
this.rgid = rgid;
this.rid = rid;
this.bigPic = bigPic;
this.smallPic = smallPic;
}
public int getRgid() {
return rgid;
}
public void setRgid(int rgid) {
this.rgid = rgid;
}
public int getRid() {
return rid;
}
public void setRid(int rid) {
this.rid = rid;
}
public String getBigPic() {
return bigPic;
}
public void setBigPic(String bigPic) {
this.bigPic = bigPic;
}
public String getSmallPic() {
return smallPic;
}
public void setSmallPic(String smallPic) {
this.smallPic = smallPic;
}
}
7. Seller
/**
* 商家实体类
*/
public class Seller implements Serializable {
private int sid;//商家id
private String sname;//商家名称
private String consphone;//商家电话
private String address;//商家地址
/**
* 无参构造方法
*/
public Seller(){
}
/**
* 构造方法
* @param sid
* @param sname
* @param consphone
* @param address
*/
public Seller(int sid, String sname, String consphone, String address) {
this.sid = sid;
this.sname = sname;
this.consphone = consphone;
this.address = address;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getConsphone() {
return consphone;
}
public void setConsphone(String consphone) {
this.consphone = consphone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
8. User
/**
* 用户实体类
*/
public class User implements Serializable {
private int uid;//用户id
private String username;//用户名,账号
private String password;//密码
private String name;//真实姓名
private String birthday;//出生日期
private String sex;//男或女
private String telephone;//手机号
private String email;//邮箱
private String status;//激活状态,Y代表激活,N代表未激活
private String code;//激活码(要求唯一)
/**
* 无参构造方法
*/
public User() {
}
/**
* 有参构方法
* @param uid
* @param username
* @param password
* @param name
* @param birthday
* @param sex
* @param telephone
* @param email
* @param status
* @param code
*/
public User(int uid, String username, String password, String name, String birthday, String sex, String telephone, String email, String status, String code) {
this.uid = uid;
this.username = username;
this.password = password;
this.name = name;
this.birthday = birthday;
this.sex = sex;
this.telephone = telephone;
this.email = email;
this.status = status;
this.code = code;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
注册功能
1. 注册功能陌生点总结
将页面滚动到页面顶部。
window.scrollTo(0,0);
获取请求地址?后面的所有参数包括?。
location.search
获取表单中所有的请求参数和参数值,拼接成key=value形式的字符串不包括?。
$(this).serialize()
2. 页面效果
3. 前台代码实现
3.1 介绍引入头部和底部通用的html
在很多网站其实顶部和底部页面部分代码其实是不经常改变的,为了满足这个需求就把公共部分提取到两个html中,然后在使用异步请求去加载这两个html放到顶部和底部。
<!--导入布局js,共享header和footer-->
<script type="text/javascript" src="js/include.js"></script>
<!--引入头部-->
<div id="header"></div>
主体html代码
<!--引入尾部-->
<div id="footer"></div>
include.js引入底部和头部html的jquery代码
$(function () {
$.get("header.html",function (data) {
$("#header").html(data);
});
$.get("footer.html",function (data) {
$("#footer").html(data);
});
});
3.2 register页面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>注册</title>
<link rel="stylesheet" type="text/css" href="css/common.css">
<link rel="stylesheet" href="css/register.css">
<!--导入jquery-->
<script src="js/jquery-3.3.1.js"></script>
</head>
<script>
//写一个页面加载事件
$(function () {
//提交表单
$("#registerForm").submit(function () {
//判断表单是否符合条件
if (checkUsername && checkPasswrod && checkEmail && checkName && checkTelephone && checkBirthday && checkCode) {
//如何就发送异步请求
$.get("registerServlet", $(this).serialize(), function (data) {
if (data.flag) {
//{"flag":false,"data":null,"errorMsg":"注册失败,用户名已经存请重新输入!"}
//注册成功
alert("注册成功