缺少依赖的jar包
The import java.sql cannot be resolved
- jre
The import javax.servlet.ServletException cannot be resolved
- tomcat
前后端交互路径
- jsp → servlet → service → daoImpl → db → jsp
dbutils的使用
MySQL的SQL语句编写
- 复习了一下MySQL的SQL语言的语法,画了一个图放在了另一篇博客。
- SQL语言基础用法-MySQL-XMind思维导图
前台,查询本周热卖商品
-
先用 LEFT JOIN 建立左连接,以 orderitem 订单项表为主,用 ON 去笛卡尔积。再用 GROUP BY 以商品 id 进行分类,用聚合函数计算销售量,然后用 SELECT 选择需要映射的列,LIMIT 方言限定行数,最后用 ORDER BY 进行降序排列。
-
SELECT products.id,products.name,products.imgurl,orderitem.buynum FROM orderitem LEFT JOIN products ON orderitem.product_id = products.id GROUP BY orderitem.product_id ORDER BY SUM(orderitem.buynum) DESC LIMIT 0,3
前台,根据名字查询商品
- 模糊查询+分页查询
SELECT * FROM products WHERE name LIKE '%" + searchfield + "%' LIMIT ?,?
- 经测试后该语句会被SQL注入,如:%’ AND 2498=2498 AND ‘%’=’,’ AND ‘%’=’,’ OR ‘%’=’,可以查询到所有商品。
- 常见的Web漏洞——SQL注入
- SQL注入-预防
前台,生成订单时将商品数量减少
- 更新操作+迭代器 foreach
UPDATE products set pnum = pnum - ? where id = ?
后台,多条件查询商品
- sql拼接+模糊查询 (\"%\"?\"%\ ")
@Override
public List<Product> findProductByManyCondition(String id, String name, String category, String minprice,
String maxprice) throws SQLException {
String sql ="select * from products where 1=1";
//存参数
List<Object> objs = new ArrayList<Object>();
if (id != null && id.trim().length() > 0) {
sql += " and id like \"%\"?\"%\"";
objs.add(id);
}
if (name != null && name.trim().length() > 0) {
sql += " and name like \"%\"?\"%\"";
objs.add(name);
}
if (category != null && category.trim().length() > 0) {
sql += " and category = ?";
objs.add(category);
}
if (minprice != null && minprice.trim().length() > 0) {
sql += " and price >= ?";
objs.add(minprice);
}
if (maxprice != null && maxprice.trim().length() > 0) {
sql += " and price <= ?";
objs.add(maxprice);
}
sql += " order by id";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
return (List<Product>) runner.query(sql, new BeanListHandler<Product>(Product.class), objs.toArray());
}
后台,查询所有订单
- 对结果集的再封装
public List<Order> findAllOrder()throws SQLException{
// 1.创建sql
String sql = "select orders.*,user.* from orders,user where user.id=orders.user_id order by orders.user_id";
// 2.创建QueryRunner对象
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
// 3.返回QueryRunner对象query()方法的查询结果
return runner.query(sql,new ResultSetHandler<List<Order>>(){
public List<Order> handle(ResultSet rs)throws SQLException{
// 创建订单集合
List<Order> orders = new ArrayList<Order>();
// 循环遍历订单和用户信息
while(rs.next()){
Order order = new Order();
order.setId(rs.getString("orders.id"));
order.setMoney(rs.getDouble("orders.money"));
order.setOrdertime(rs.getDate("orders.ordertime"));
order.setPaystate(rs.getInt("orders.paystate"));
order.setReceiverAddress(rs.getString("orders.receiverAddress"));
order.setReceiverName(rs.getString("orders.receiverName"));
order.setReceiverPhone(rs.getString("orders.receiverPhone"));
User user = new User();
user.setId(rs.getInt("user.id"));
user.setEmail(rs.getString("user.email"));
user.setGender(rs.getString("user.gender"));
user.setActiveCode(rs.getString("user.activecode"));
user.setIntroduce(rs.getString("user.introduce"));
user.setPassword(rs.getString("user.password"));
user.setRegistTime(rs.getDate("user.registtime"));
user.setRole(rs.getString("user.role"));
user.setState(rs.getInt("user.state"));
user.setTelephone(rs.getString("user.telephone"));
user.setUsername(rs.getString("user.username"));
order.setUser(user);
orders.add(order);
}
return orders;
}
});
}
java.io.Serializable接口
- serialVersionUID 用来表明实现序列化类的不同版本间的兼容性。
- 为了在反序列化时,确保类版本的兼容性,最好在每个要序列化的类中加入private static final long serialVersionUID这个属性,具体数值自己定义。
tomcat错误
Server Tomcat v9.0 Server at localhost failed to start.
session中User对象判空
- 前端传过来的对象时,单纯的使用 object == null 去判断是不够的,因为前端传过来的对象会是对象不为null,但是对象的所有属性均为null。(boolean类型除外,以及序列化值除外)
- Java判断对象是否为NULL
- 当前端没有对象时,使用该语句 user = (User) request.getSession().getAttribute(“user”); 会发生NPE异常,我这里将用户未登录所需要重定向的路径放在了catch中。
正则表达式
- js正则与Java正则类似,我写的这篇Java正则的博客可以参考。
- Java正则表达式-详解
BeanUtils 以及 BeanUtils.populate 使用
- BeanUtils是一个主要应用于Bean的Util。
- BeanUtils 以及BeanUtils.populate使用
getParameterMap()
- JAVA中的request.getParameterMap(),使用BeanUtils工具类封装请求参数。
- request.getParameterMap
在 js 中动态获取 session,和使用 try-catch
function user_login(){
try{
var a="${user.username}";
if(a != null && a != "" && a != ""){
return true;
}else{
var flag = window.confirm("请您先登陆");
return false;
}
}catch(err){
var flag = window.confirm("请您先登陆");
return false;
}
}
跳转页面产生新页签
- 添加 target="_blank"
<a href="${pageContext.request.contextPath}/index.jsp" target="_blank"
onclick="javascript:return confirm_logout();">返回前台</a>
sendRedirect 和 forward 的区别
- sendRedrect()重定向:不仅可以重定向到同一web应用中的组件,可以重定向到其他站点资源,重定向后浏览器的URL会发生变化,因为重定向的实质 是 server端发送一个消息给浏览器端,使重新浏览新的URL。
- forward() 请求转发:forward只能请求转发给同一web应用中的组件,转发后浏览器的url不会发生改变,forward实质是 站内转发,获取其他server资源,不会给浏览器端发送消息。
servlet - 添加商品
- 这里的重点主要是对于文件的操作
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 创建javaBean,将上传数据封装.
Product p = new Product();
Map<String, String> map = new HashMap<String, String>();
// 封装商品id
map.put("id", IdUtils.getUUID());
DiskFileItemFactory dfif = new DiskFileItemFactory();
// 设置临时文件存储位置
dfif.setRepository(new File(this.getServletContext().getRealPath("/temp")));
// 设置上传文件缓存大小为10m
dfif.setSizeThreshold(1024 * 1024 * 10);
// 创建上传组件
ServletFileUpload upload = new ServletFileUpload(dfif);
// 处理上传文件中文乱码
upload.setHeaderEncoding("utf-8");
try {
// 解析request得到所有的FileItem
List<FileItem> items = upload.parseRequest(request);
// 遍历所有FileItem
for (FileItem item : items) {
// 判断当前是否是上传组件
if (item.isFormField()) {
// 不是上传组件
String fieldName = item.getFieldName(); // 获取组件名称
String value = item.getString("utf-8"); // 解决乱码问题
map.put(fieldName, value);
} else {
// 是上传组件
// 得到上传文件真实名称
String fileName = item.getName();
fileName = FileUploadUtils.subFileName(fileName);
// 得到随机名称
String randomName = FileUploadUtils.generateRandonFileName(fileName);
// 得到随机目录
String randomDir = FileUploadUtils.generateRandomDir(randomName);
// 图片存储父目录
String imgurl_parent = "/productImg" + randomDir;
File parentDir = new File(this.getServletContext().getRealPath(imgurl_parent));
// 验证目录是否存在,如果不存在,创建出来
if (!parentDir.exists()) {
parentDir.mkdirs();
}
String imgurl = imgurl_parent + "/" + randomName;
map.put("imgurl", imgurl);
IOUtils.copy(item.getInputStream(), new FileOutputStream(new File(parentDir, randomName)));
item.delete();
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
try {
// 将数据封装到javaBean中
BeanUtils.populate(p, map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
ProductService service = new ProductService();
try {
// 调用service完成添加商品操作
service.addProduct(p);
response.sendRedirect(request.getContextPath() + "/listProduct");
return;
} catch (RuntimeException e) {
e.printStackTrace();
response.getWriter().write("添加商品失败");
return;
}
}
service - 删除订单
对多个表进行增加、修改或删除,需要开启事务,若有一个不成功就发生回滚。
// 普通用户删除订单
public void delOrderByIdWithClient(String id){
try{
// 开启事务
DataSourceUtils.startTransaction();
// 从订单项中查找商品购买数量
Order order=new Order();
order.setId(id);
List<OrderItem> items=oidao.findOrderItemByOrder(order);
// 修改商品数量
pdao.updateProductNum(items);
// 删除订单项
oidao.delOrderItems(id);
// 删除订单
odao.delOrderById(id);
}catch(SQLException e){
e.printStackTrace();
try{
DataSourceUtils.rollback();
}catch(SQLException e1){
e1.printStackTrace();
}
}finally{
try{
DataSourceUtils.releaseAndCloseConnection();
}catch(SQLException e){
e.printStackTrace();
}
}
}
String的格式化 - time的显示
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
NoticeService nService = new NoticeService();
List<Notice> notices = nService.getAllNotices();
for (Notice notice : notices) {
String time = notice.getN_time();
String temp = String.format("%s-%s-%s %s:%s:%s", time.substring(0, 4),time.substring(4, 6),time.substring(6,8),
time.substring(8, 10),time.substring(10, 12),time.substring(12, 14));
notice.setN_time(temp);
}
req.setAttribute("notices", notices);
req.getRequestDispatcher("/admin/notices/list.jsp").forward(req, resp);
}
所用到的五个工具类
- 篇幅较长,我这里放在了另一篇博客上。
- 网上书城项目-暂时用到的五个工具类-Javaweb
filter监听器和web.xml的配置
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
/**
* Servlet Filter implementation class EncodingFilter
*/
@WebFilter("/EncodingFilter")
public class EncodingFilter implements Filter {
// 定义替换后的字符集,从过滤器的配置参数中读取
private String characterEncoding;
/**
* Default constructor.
*/
public EncodingFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("web.xml中该过滤器配置的encoding值为" + characterEncoding);
request.setCharacterEncoding(characterEncoding);
response.setContentType("text/html;charset=" + characterEncoding);
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// 获取web.xml中filter配置的参数
if (fConfig.getInitParameter("encoding") != null) {
characterEncoding = fConfig.getInitParameter("encoding");
} else {
characterEncoding = "UTF-8";
}
}
}
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>bookstore.web.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
服务器端搭建web环境
- 之前已经安装过 jdk1.8 和 tomcat9,经测试可用。这次安装的是 MySQL5.7。环境是阿里云的ecs服务器Ubuntu18无GUI。
- 一系列的问题,我放在了另一篇博客。
- MySQL5.7的安装、配置、远程连接-Ubuntu18
- 项目的部署:将项目打包成war文件放在tomcat的webapps下,重启tomcat。
项目运行出现的问题
MySQL5.7与MySQL5.5的差异,导致项目直接运行失败。(我电脑上是5.5,服务器上是5.7)
问题出现的原因:
MySQL 5.7.5及以上功能依赖检测功能。如果启用了ONLY_FULL_GROUP_BY SQL模式(默认情况下),MySQL将拒绝选择列表,HAVING条件或ORDER BY列表的查询引用在GROUP BY子句中既未命名的非集合列,也不在功能上依赖于它们。(5.7.5之前,MySQL没有检测到功能依赖关系,默认情况下不启用ONLY_FULL_GROUP_BY。有关5.7.5之前的行为的说明,请参见“MySQL 5.6参考手册”。)
将eclipse项目导入到idea
使用 Alibaba Cloud Toolkit 中间件 部署项目
- 在 Intellij IDEA 中部署 Java 应用到 阿里云 ECS
- 我这里需要配置的路径和命令如下:
文件存放路径:home/xxx/tomcat9/webapps
启动tomcat命令:sh /home/xxx/tomcat9/bin/startup.sh