前言
1、本篇仅记录本人在一学期的Java Web课程中学习所遇到一些问题及解决方法,可能不会适用于所有人。
2、代码并非本人原创,前端代码大部分为网络下载,Servlet代码为网络查找改写,如有侵权,必删。
正文
一、项目开发环境及工具
我所使用的的是JDK1.8,mysql8.0.29,tomcat8以及maven3.8.5
开发工具则使用IDEA,Navicat15,powerdesigner16.5
二、项目开发所需要做的准备
2.1 数据库
确定好数据库所需内容,也就是Java项目里的实体类,确定好类与类之间的关系,这是我在做项目时使用pd16.5软件所生成的数据库关系图。关于pd16.5的使用,可以自行查找。
2.2 C3P0
C3P0作为Java与数据库连接的一个重要配置文件,在mysql更新至8版本以后,会出现大量问题,比如时区不同步,连接超时等。这些问题同样也困扰了我许久,在网络寻觅几小时后,终于是找到了一个比较全面的配置,如下:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/shopping?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false&allowPublicKeyRetrieval=true</property>
<property name="user">root</property>
<property name="password">mama2929</property>
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">3</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">200</property>
<property name="maxIdleTime">1800</property>
<property name="idleConnectionTestPeriod">1800</property>
<property name="maxStatements">0</property>
<property name="checkoutTimeout">10000</property>
<property name="acquireRetryAttempts">5</property>
<property name="acquireRetryDelay">1000</property>
<property name="numHelperThreads">5</property>
<property name="testConnectionOnCheckout">true</property>
<property name="preferredTestQuery">select 1</property>
</default-config>
</c3p0-config>
三、项目的开发
既然是要做JavaWeb,那必然少不了前端页面与后端服务器的连接,而本次课程设计使用的是JSP与Servlet为主的开发。
3.1 前端页面展示
3.2 Servlet部分代码展示
AddressController
@WebServlet("/address")
public class AddressController extends BaseServlet {
public String show(HttpServletRequest request, HttpServletResponse response) throws SQLException {
HttpSession session = request.getSession();
User user = (User) session.getAttribute("loginUser");
if (user == null)
{
session.setAttribute("msg", "需要先登录!");
return Constants.REDIRECT + "/login.jsp";
}
int uid = user.getUid();
AddressService addressService = new AddressServiceImpl();
List<Address> addresses = addressService.findAddressByUid(uid);
request.setAttribute("list", addresses);
return Constants.FORWARD + "/self_info.jsp";
}
public String add(HttpServletRequest request,HttpServletResponse response) throws InvocationTargetException, IllegalAccessException, SQLException {
//1.获取请求参数
Map<String, String[]> map = request.getParameterMap();
Address address = new Address();
BeanUtils.populate(address,map);
//2.调用业务逻辑进行地址添加
AddressService addressService = new AddressServiceImpl();
addressService.saveAddress(address);
//3。转发到展示的方法
return Constants.FORWARD + "/address?method=show";
}
public String delete(HttpServletRequest request,HttpServletResponse response) throws InvocationTargetException, IllegalAccessException, SQLException {
//1.获取请求参数
String aid = request.getParameter("aid");
//2.调用业务逻辑进行地址添加
AddressService addressService = new AddressServiceImpl();
addressService.deleteAddressByAid(aid);
//3。转发到展示的方法
return Constants.FORWARD + "/address?method=show";
}
public String setDefault(HttpServletRequest request,HttpServletResponse response) throws InvocationTargetException, IllegalAccessException, SQLException {
//1.获取请求参数
String aid = request.getParameter("aid");
HttpSession session = request.getSession();
User user = (User) session.getAttribute("loginUser");
if (user == null)
{
session.setAttribute("msg", "需要先登录!");
return Constants.REDIRECT + "/login.jsp";
}
//2.调用业务逻辑进行地址添加
AddressService addressService = new AddressServiceImpl();
addressService.setAddressToDefault(aid,user.getUid());
//3。转发到展示的方法
return Constants.FORWARD + "/address?method=show";
}
public String update(HttpServletRequest request,HttpServletResponse response) throws InvocationTargetException, IllegalAccessException, SQLException {
//1.获取请求参数
Map<String, String[]> map = request.getParameterMap();
Address address = new Address();
BeanUtils.populate(address,map);
//2.调用业务逻辑进行地址添加
AddressService addressService = new AddressServiceImpl();
addressService.updateByAid(address);
//3。转发到展示的方法
return Constants.FORWARD + "/address?method=show";
}
}
UserController
@WebServlet("/user")
public class UserController extends BaseServlet{
public void check(HttpServletRequest request, HttpServletResponse response) throws SQLException, IOException {
PrintWriter out = response.getWriter();
//1.获取用户
String username = request.getParameter("username");
if (username == null){
out.println(JSON.toJSON(Constants.HAS_USER));
return;
// return Constants.HAS_USER;//不能注册
}
//2.调用业务逻辑 判断用户名是否存在
UserService userService = new UserServiceImpl();
boolean b = userService.checkUser(username);
//3.响应字符串 1 存在 0 不存在
if (b) {
//用户存在
out.println(JSON.toJSON(Constants.HAS_USER));
return;
// return Constants.HAS_USER;
}
out.println(JSON.toJSON(Constants.NOT_HAS_USER));
// return Constants.NOT_HAS_USER;
}
public void register(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter();//加在第一行
//1获取用户信息
Map<String, String[]> parameterMap = request.getParameterMap();
User user=new User();
try {
BeanUtils.populate(user,parameterMap);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//2完善用户信息
//已赋值,用户名 密码 邮箱 性别
//没赋值,激活状态 账号类型 激活码
user.setUstatus(Constants.USER_NOT_ACTIVE);//未激活状态0 激活 1
user.setUrole(Constants.ROLE_CUSTOMER);//普通客户0 管理员1
user.setCode(RandomUtils.createActive());
//需要处理的属性,密码md5进行加密处理
user.setUpassword(MD5Utils.md5(user.getUpassword()));
//3调用用户的业务逻辑进行注册
UserService userService = new UserServiceImpl();
try {
userService.registerUser(user);
} catch (SQLException e) {
e.printStackTrace();
request.setAttribute("registerMsg","注册失败!");
out.println(JSON.toJSON("注册失败"));
return;
// return Constants.FORWARD+"/register.jsp";
}
//4响应
out.println(JSON.toJSON("注册成功"));
// return Constants.FORWARD + "/registerSuccess.jsp";
}
public String active(HttpServletRequest request,HttpServletResponse response) throws SQLException {
//1获取激活码
//已经转成Base64
String c = request.getParameter("c");
//base64翻转
String code= Base64Utils.decode(c);
//2调用激活的业务逻辑
UserService userService = new UserServiceImpl();
int i = userService.activeUser(code);
//3响应(激活失败(code没找到) 已经激活 激活成功)
if(i==Constants.ACTIVE_FAIL){
request.setAttribute("msg","未激活成功!");
}else if (i==Constants.ACTIVE_SUCCESS){
request.setAttribute("msg","激活成功,请登录!");
}else {
request.setAttribute("msg","已经激活,请登录!");
}
return Constants.FORWARD+ "/message.jsp";
}
/**
* 1.前端提交账号密码和验证码
* 2对比验证码 成功 --->对比账号密码
* 3对比账号密码
* 失败 --> 回到登录页面 进行提示
* 成功 --> 未激活 登录页面 进行提示
* --> 已激活 程序首页 将用户放入session共享域
*/
public String login(HttpServletRequest request,HttpServletResponse response) throws SQLException {
//1获取请求参数(用户名,密码,验证码)
String username = request.getParameter("username");
String password = request.getParameter("password");
String code = request.getParameter("code");//用户输入验证码
String auto=request.getParameter("auto");//自动登录
//正确验证码
HttpSession session = request.getSession();
String codestr = (String) session.getAttribute("code");
//2判断验证码是否正确
if (code == null || !code.equalsIgnoreCase(codestr)){
request.setAttribute("msg","验证码错误");
return Constants.FORWARD + "/login.jsp";
}
//3调用业务逻辑判断账号密码
UserService userService=new UserServiceImpl();
User user = userService.login(username, password);
//4响应
//user等于Null 证明账号或密码错误
//user 不为空 但是user状态未激活
if (user==null){
request.setAttribute("msg","账号或密码错误");
return Constants.FORWARD+"/login.jsp";
}
if (user.getUstatus().equals(Constants.USER_NOT_ACTIVE)){
request.setAttribute("msg","账号未激活");
return Constants.FORWARD+"/login.jsp";
}
session.setAttribute("loginUser",user);
//autoUser
//1.判断是否勾选自动登录
if (auto == null){
//没有勾选
//将本地浏览器的存在的cookie‘清空’
Cookie cookie = new Cookie(Constants.AUTO_NAME,"");
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
}else{
//自动登录数据库存储 2周
String content = username+Constants.FLAG+password;
content = Base64Utils.encode(content);
Cookie cookie = new Cookie(Constants.AUTO_NAME,content);
cookie.setPath("/");
cookie.setMaxAge(14*24*60*60);
response.addCookie(cookie);
}
return Constants.REDIRECT+"/index.jsp";
}
/**
* 注销登录 清空数据 跳转登录页面
* @param request
* @param response
* @return
*/
public String logOut(HttpServletRequest request,HttpServletResponse response){
//清空session中用户数据
HttpSession session = request.getSession();
session.removeAttribute("loginUser");
//2清空和覆盖cookie存储的自动登录信息
Cookie cookie = new Cookie(Constants.AUTO_NAME,"");
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
//3转发登录页面
request.setAttribute("msg","注销登录成功");
return Constants.FORWARD + "/login.jsp";
}
}
ProductDaoImpl
public class ProductDaoImpl implements ProductDao {
@Override
public long selectCountByTid(String tid) throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql ="select count(1) from product where t_id = ?";
Object result = queryRunner.query(sql,new ScalarHandler(),tid);
Long total = (long) result;
return total;
}
@Override
public List<Product> selectProductByPage(int page, int pageSize, String tid) throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql ="select p_id as pid,t_id as tid,p_name as pname,p_time as ptime ," +
"p_image as pimage,p_state as pstate ,p_info as pinfo ,p_price as pprice " +
"from product where t_id = ? limit ?,?;";
List<Product> list = queryRunner.query(sql, new BeanListHandler<Product>(Product.class),
tid, (page - 1) * pageSize, pageSize);
return list;
}
@Override
public Product selectProductByPid(String pid) throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql ="select p_id as pid,t_id as tid,p_name as pname,p_time as ptime ," +
"p_image as pimage,p_state as pstate ,p_info as pinfo ,p_price as pprice " +
"from product where p_id = ? ;";
Product product = queryRunner.query(sql, new BeanHandler<Product>(Product.class), pid);
return product;
}
}
CartDaoImpt
public class CartDaoImpl implements CartDao {
@Override
public Cart hasCart(int uid, String pid) throws SQLException, InvocationTargetException, IllegalAccessException {
//cart --> product 连接查询 多表查询
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select p.p_name as pname,p.p_id as pid,p.t_id as tid," +
"p.p_time as ptime,p.p_image as pimage,p_state as pstate," +
"p.p_info as pinfo, p.p_price as pprice,c.c_id as cid,c.u_id as uid,c.c_count as ccount," +
"c.c_num as cnum from product p join cart c on p.p_id = c.p_id where" +
" c.u_id = ? and c.p_id = ?;";
Map<String, Object> query = queryRunner.query(sql, new MapHandler(), uid, pid);
Map<String, Object> queryReplace = new HashMap<>();
System.out.println(query);
System.out.println(uid+" "+pid);
if (query == null) {
return null;
}else{
for(String key : query.keySet()){
String temp = key.split("_")[0] + key.split("_")[1];
queryReplace.put(temp,query.get(key));
}
}
Cart cart = new Cart();
Product product = new Product();
BeanUtils.populate(cart,queryReplace);
BeanUtils.populate(product, queryReplace);
cart.setProduct(product);
return cart;
}
@Override
public void updateCart(Cart cart) throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "update cart set c_num = ? , c_count = ? where c_id = ?";
queryRunner.update(sql, cart.getCnum(),cart.getCcount(),cart.getCid());
}
@Override
public void insertCart(Cart cart) throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "insert into cart (u_id,p_id,c_num,c_count) value(?,?,?,?)";
queryRunner.update(sql, cart.getUid(),cart.getProduct().getPid(),cart.getCnum(),cart.getCcount());
}
@Override
public List<Cart> selectCartsByUid(int uid) throws InvocationTargetException, IllegalAccessException, SQLException {
//注意 查询cart需要关联到商品表
//cart --> product 连接查询 多表查询
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select p.p_name as pname,p.p_id as pid,p.t_id as tid," +
"p.p_time as ptime,p.p_image as pimage,p_state as pstate," +
"p.p_info as pinfo, p.p_price as pprice,c.c_id as cid,c.u_id as uid,c.c_count as ccount," +
"c.c_num as cnum from product p join cart c on p.p_id = c.p_id where" +
" c.u_id = ?;";
List<Map<String, Object>> list = queryRunner.query(sql, new MapListHandler(), uid);
if (list == null){
return null;
}
List<Cart> carts = new ArrayList<>();
for (Map<String, Object> map : list) {
//cart + product
Cart cart = new Cart();
Product product = new Product();
Map<String, Object> queryReplace = new HashMap<>();
for(String key : map.keySet()){
String temp = key.split("_")[0] + key.split("_")[1];
queryReplace.put(temp,map.get(key));
}
BeanUtils.populate(cart, queryReplace);
BeanUtils.populate(product,queryReplace);
cart.setProduct(product);
carts.add(cart);
}
return carts;
}
@Override
public void deleteCartByCid(String cid) throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "delete from cart where c_id = ?;";
queryRunner.update(sql, cid);
}
@Override
public void updateByCid(BigDecimal count, BigDecimal cnumbig, String cid) throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "update cart set c_count = ? , c_num = ? where c_id = ?;";
queryRunner.update(sql, count,cnumbig,cid);
}
@Override
public void deleteCartByUid(String uid) throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "delete from cart where u_id = ?;";
queryRunner.update(sql, uid);
}
}
四、总结
写这个代码时,遇到了许许多多的问题,就比如:关于BeanUtils工具类的使用,.popular的使用,是要求Bean值与Key值完全相同,而在代码中,数据库的命名为 B_id,在Java实体类中的命名则为Bid,这样就导致查找不到,从而无法实现赋值,关于这个问题的解决方法,只需分割“_”即可解决
for (Map<String, Object> map : list) {
//cart + product
Cart cart = new Cart();
Product product = new Product();
Map<String, Object> queryReplace = new HashMap<>();
for(String key : map.keySet()){
String temp = key.split("_")[0] + key.split("_")[1];
queryReplace.put(temp,map.get(key));
}
BeanUtils.populate(cart, queryReplace);
BeanUtils.populate(product,queryReplace);
cart.setProduct(product);
carts.add(cart);
}
如果在数据库中有Datetime数据,在Java中定义实体类为Date型时,可能会导致无法从String型转为Date型,这是因为BeanUtils工具只支持转换 java.sql.Date。所以一定检查自己的实体类使用的是什么包。 当然,仅仅是使用sql包并不能真正解决这个问题,还需在DaoImpt中做一些代码的修改,将存储的数据类型进行转化
ConvertUtils.register(new Converter() {
@Override
public Object convert(Class clazz, Object value) {
//将String转化为date
Date parse=null;
try {
//parse()返回的是一个Date类型数据,format返回的是一个StringBuffer类型的数据
// parse = (Date) format.parse(value.toString());
LocalDateTime localDateTime = (LocalDateTime) value;
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
Instant instant = zonedDateTime.toInstant();
java.util.Date date= Date.from(instant);
parse=new java.sql.Date(date.getTime());
} catch (Exception e) {
e.printStackTrace();
}
return parse;
}
}, Date.class);