图书商城_day1遇到的难点

管理员界面

添加图书

管理员中,需要添加图书,那么这时候我们需要利用到了文件上传,此时,文件上传的基本步骤为:

1、jsp界面中:
     - form标签中的method属性值为post,并且需要含有enctype属性,值为multipart/form-data
     - form标签中还需要有<input type="file"...>的子标签
2、servlet代码中
在Servlet中,不可以通过request调用getParameter来获取表单的数据,而是需要先进
行解析之后获取表单项的数据。解析的基本步骤为:
   - 创建工厂DiskFileItemFactory
   - 创建解析器对象ServletFileUpload
   - 解析器对象调用parseRequest方法来进行解析request

这里需要一提的是,如果我们将表单数据已经解析过一次之后,那么如果再次解析的时候,那么返回的表单项列表List<FileItem>虽然不为null,但是元素个数却是0.这是可以通过parseRequest方法源码可以看到。.
例如我们项目中,首先需要BaseServlet来获取method参数对应的值,但是这时候method这个是一个表单项的值,那么这时候如果直接调用getParameter方法的话,那么返回的是null,所以这时候我们就需要进行上面的2中的方法来解析表单项
但是这时候解析完毕之后,虽然我们已经获取到了method这个参数对应的值method_name,然后在BaseServlet中利用反射来调用对应的方法,但是这时候我们在method_name这个方法中,再次解析表单项的数据的时候,就会发现元素个数为0了。
因此,我们需要在第一次解析的时候,将表单项的内容保存到request域中,这样执行method_name方法的时候,不需要再进行解析,就可以获取表单项的内容了

所以我们对应的BaseServlet代码如下:

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取方法,注意的是
        String method_name = request.getParameter("method");
        if(method_name == null){
            //可能是需要上传文件,所以我们还需要获取表单项,判断表单中是否存在method这个参数
            //1、创建工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //2、创建解析器
            ServletFileUpload fileUpload = new ServletFileUpload(factory);
            //3、调用方法进行解析
            try {
                List<FileItem> fileItems = fileUpload.parseRequest(request);
                //遍历表单项,判断是否存在method这个表单项
                for(FileItem item : fileItems){
                    String fieldName = item.getFieldName();
                    //将表单项中的内容保存到request域中
                    switch(fieldName){
                        case "method":
                            method_name = item.getString("utf-8");//获取这个表单项的内容,并且使用的是utf-8进行编码
                            break;
                        case "name":
                            request.setAttribute("name",item.getString("utf-8"));
                            break;
                        case "price":
                            request.setAttribute("price",item.getString("utf-8"));
                            break;
                        case "catagory_id":
                            request.setAttribute("catagory_id",item.getString("utf-8"));
                            break;
                        case "image"://文件表单项
                            //获取对应的文件
                            request.setAttribute("image",item.getInputStream());
                    }
                }
                if(method_name == null){
                    throw new RuntimeException("没有传递method参数");
                }
                System.out.println("method_name = " + method_name);
            } catch (FileUploadException e) {
                e.printStackTrace();
            }
        }
        Class clazz = this.getClass();
        try {
            /*
            因为在执行BaseServlet之前,我们还定义了filter来解决全站的乱码问题,然后才可以
            方向,这时候,如果调用的是request.getClass,那么就会发生报错,因为这时候
            request.getClass() = org.apache.catalina.connector.RequestFacade,
            response.getClass() = org.apache.catalina.connector.ResponseFacade
            我们自定义的子类中,并没有这样的方法,而是(HttpServletRequest.class,HttpServletResponse.class)
            Method method = clazz.getMethod(method_name, request.getClass(), response.getClass());
             */

            Method method = clazz.getMethod(method_name, HttpServletRequest.class, HttpServletResponse.class);
            //调用对应的方法
            String str = (String)method.invoke(this,request, response);
            if(str == null){
                //如果没有返回值的话,那么直接返回
                return;
            }
            //根据返回值,然后进行转发
            int index = str.indexOf(":");//判断是否存在冒号
            if(index == -1){
                //不存在冒号,那么默认进行转发操作
                request.getRequestDispatcher(str.substring(index + 1))
                        .forward(request,response);
            }else{
                String path = str.substring(index + 1);
                //根据冒号前面的字符串,判断进行的是重定向还是转发操作
                String operation = str.substring(0,index);
                if(operation.equals("f")){
                    request.getRequestDispatcher(path)
                            .forward(request,response);
                }else{
                    //如果是以r开头,那么就是进行重定向操作
                    response.sendRedirect(path);
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

获取图书

因为数据库中的image类型为Blob,如果这时候我们定义的Book实体中的image属性是一个Blob类型的,那么执行下面的sql语句就会发生报错,提示:error: incompatible types,cannot convert [B to java.sql.Blob......,这时候尽管Book实体中的image是一个Blob,但是依旧会发生错误。网上我查的时候说Blob是一个接口,不可以示例化,这个原因并没有弄清,有大佬知道的话,请指教哈!!!

String sql = "select b.id," + 
                     "b.name," + 
                     "c.name as catagory_name," +
                     "b.price," + 
                     "b.image " +
             "from book as b inner join catagory as c " +
             on b.catagory_id = c.id";
List<Book> bookLists = qr.query(connection,sql,new BeanListHandler<Book>(Book.class));

所以最后决定数据库中的image虽然是一个Blob类型,但是我获取当一个Blob的时候,就创建对应的图片,保存到项目中的"web/images/"目录下,文件名以当前图片的名字命名.

public List<Book> query() throws SQLException, IOException {
        Connection connection = JDBCUtils.getConnection();
        String sql = "select b.id,b.name as name,c.name as catagory_name,b.price,b.image " +
                "from book as b inner join catagory as c " +
                "on b.catagory_id = c.id";
        PreparedStatement psmt = connection.prepareStatement(sql);
        ResultSet resultSet = psmt.executeQuery();
        List<Book> bookLists = new ArrayList<>();
        while(resultSet.next()){
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            String catagory_name = resultSet.getString("catagory_name");
            double price = resultSet.getDouble("price");
            Blob image = resultSet.getBlob("image");//获取到数据库中类型为Blob的数据之后,将获取对应的流
            InputStream in = image.getBinaryStream();
            String path = "E://IDEAworkspace/代码/复习/网上书城/web/images/" + name + ".png";//图片存放的路径
            FileOutputStream out = new FileOutputStream(path);
            IOUtils.copy(in,out);//利用IOUtils,从而将in中的内容copy到out中
            bookLists.add(new Book(id,name,catagory_name,price));
        }
        psmt.close();
        JDBCUtils.releaseConnection(connection);

        return bookLists;
    }

获取到图片之后,已经存在了路径,那么我们可以将bookList存放到request域中,这样就可以回显数据了。
bookList.jsp界面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>查询图书</title>
</head>
<body>
<div id="main">
    <div id="right">
        <c:if test="${not empty requestScope.books}">
            <table>
                <thead>
                   <td>图书图片</td>
                   <td>图书名字</td>
                   <td>图书分类</td>
                   <td>图书价格</td>
                   <td>操作</td>
                </thead>
                <c:forEach items="${requestScope.books}" var="book">
                    <tr>
                        <td><img src="<c:url value='/images/${book.name}.png'></c:url>"></td>
                        <td>${book.name}</td>
                        <td>${book.catagory_name}</td>
                        <td>${book.price}</td>
                        <td>
                            <a href="#">编辑</a>
                            <a href="#">删除</a>
                        </td>
                    </tr>
                </c:forEach>
            </table>
        </c:if>
    </div>
    </div>
</body>
</html>

这时候如果我们没有设置安装tomcat目录下面的server.xml的话,那么很容易导致图片加载不出来,我们点击F12会发现,提示发生错误,原来是因为将图片名中的中文变成了URL编码,从而导致无法加载图片,这时候我们来修改server.xml文件,我们只需要
在这里插入图片描述
可以参考一下这个文章:关于JavaWeb中图片无法加载的解决方法

设置某一个标签的值或者触发事件是,发生报错Cannot set properties of null (setting ‘xxx’)

这个通常是因为标签对象为null所导致的,就好像我们的java中,假设对象A,想要调用它的方法display(),那么应该是先实例化A,然后再去调用方法display,否则如果对象A为null,那么就会发生报错。而这里发生这样的错误是同样的道理,如果我们获取到的标签为null,那么这时候设置它的属性,或者设置触发事件的时候就会发生报错了。所以这时候我们通常需要来检查一下我们获取到的标签对象是否为null,可以看一下getElementById(“xxx”)的值和我们定义的标签中的是否一致即可

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值