java web project--learning through building 2

Tue, Jan 12, 2021 5-minute read

a full-stack web application for users to understand java web system

jQuery

attr()

prop() (checked, readOnly, selected, disabled)

xml

Servlet

HttpServlet

in real life always use HttpServlet instead of the GenericServlet. HttpServlet is easier to work with, and has more methods to work with than GenericServlet.

/

/ decode by web

. <a href="/"> / </a> / is a absolute path: http:ip:port/

/ decode by service

<url-pattern>/servlet </url-pattern>/ is a absolute path: http:ip:port/project

servletContext.getRealPath("/")

request.getRequestDispatcher("/")

reponse.sendRediect("/") // send / to web get http:ip:port/

garbled languagee

resp.setContentType(“text/html; charset=UTF-8”);

JavaEE three-tier system, decouple

client(Web Browser)

⬇️

JaveEE three-tier system

⬇️

1️⃣ web/view

    1. get request parameter, encapsulate into a single standardized Bean object;
    1. invoke Service layer to deal with business;
    1. response to client, sendRediect, getRequestDispatcher;

⬇️ ⬇️

2️⃣ Serveice

    1. deal with business layer
    1. invoke Dao save date

⬇️ ⬇️

3️⃣ Dao persistence layer

  • only interact with Sql
    • CRUD
    • Create
    • Read
    • Update
    • Delete

⤵️

MySQL, Oracle, SqlServer

↩️

  • Dao
    • Jdbc
    • DbUtile
    • JdbcTemplate
    • Mybatis
    • Hiberante
    • JPA

↩️

  • Serveice
    • Spring frame

↩️

  • Web
    • Service
    • Webwork
    • Strtus1.x/2.x
    • SpringMVC

servlet thymeleaf

index

index -》 IndexServlet (service() -》 doGet() ) -》《- xxDAOImpl -》 《- BaseDAO -》 《- 向数据库发起请求 -》 IndexServlet (service() -》 doGet() ) -》《- xxDAOImpl -》 《- BaseDAO -》 《- 向数据库发起请求

Thymeleaf 视图模板技术

  • 添加 Thymeleaf jar 包
  • web.xml 添加配置
  • 新建一个 ViewBaseServlet
    • 配置前缀 prefix
    • 配置后缀 suffix
  • servlet 继承 ViewBaseServlet

ViewBaseServlet

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

TemplateEngine 用法

index th:if && th:less 用法

th:if 是条件为 true

<tr th:if="${#lists.isEmpty(session.bookList)}">
    <td colspan="4">库存为空</td>
</tr>

th:unless 是条件为 false

<tr th:unless="${#lists.isEmpty(session.bookList)}">
    <td>book1</td>
    td>200</td>
    td>30</td>
</tr>

@WebServlet("/edit.do") put/get 问题

先理解只要不是 form 表单,修改也是 get

游览器只能发送 get 和 post

引进 dispatchServlet 后代码改变

image

springmvc

servlets 合并

  • AddServlet.java
image

servlets

@WebServlet("/add.do")
public class AddServlet extends ViewBaseServlet {

    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String fname = request.getParameter("fname");
        Integer price = Integer.parseInt(request.getParameter("price")) ;
        Integer fcount = Integer.parseInt(request.getParameter("fcount"));
        String remark = request.getParameter("remark");

        Fruit fruit = new Fruit(0,fname , price , fcount , remark ) ;

        fruitDAO.addFruit(fruit);

        response.sendRedirect("index");

    }
}
  • Servelt 过多
image

servlets

在方法中用

switch{ case “index” }

image

servlets


@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {
    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置编码
        request.setCharacterEncoding("UTF-8");

        String operate = request.getParameter("operate");
        if(StringUtil.isEmpty(operate)){
            operate = "index" ;
        }

        switch(operate){
            case "index":
                index(request,response);
                break;
            case "add":
                add(request,response);
                break;
            case "del":
                del(request,response);
                break;
            case "edit":
                edit(request,response);
                break;
            case "update":
                update(request,response);
                break;
            default:
                throw new RuntimeException("operate值非法!");
        }
    }

    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
        request.setCharacterEncoding("utf-8");

        //2.获取参数
        String fidStr = request.getParameter("fid");
        Integer fid = Integer.parseInt(fidStr);
        String fname = request.getParameter("fname");
        String priceStr = request.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = request.getParameter("remark");

        //3.执行更新
        fruitDAO.updateFruit(new Fruit(fid,fname, price ,fcount ,remark ));

        //4.资源跳转
        //super.processTemplate("index",request,response);
        //request.getRequestDispatcher("index.html").forward(request,response);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取furitList,然后覆盖到session中,这样index.html页面上显示的session中的数据才是最新的
        response.sendRedirect("fruit.do");
    }

    private void edit(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        String fidStr = request.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            request.setAttribute("fruit",fruit);
            super.processTemplate("edit",request,response);
        }
    }

    private void del(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        String fidStr = request.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);

            //super.processTemplate("index",request,response);
            response.sendRedirect("fruit.do");
        }
    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String fname = request.getParameter("fname");
        Integer price = Integer.parseInt(request.getParameter("price")) ;
        Integer fcount = Integer.parseInt(request.getParameter("fcount"));
        String remark = request.getParameter("remark");

        Fruit fruit = new Fruit(0,fname , price , fcount , remark ) ;

        fruitDAO.addFruit(fruit);

        response.sendRedirect("fruit.do");

    }

    private void index(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        HttpSession session = request.getSession() ;

        // 设置当前页,默认值1
        Integer pageNo = 1 ;

        String oper = request.getParameter("oper");

        //如果oper!=null 说明 通过表单的查询按钮点击过来的
        //如果oper是空的,说明 不是通过表单的查询按钮点击过来的
        String keyword = null ;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1 , keyword应该从请求参数中获取
            pageNo = 1 ;
            keyword = request.getParameter("keyword");
            //如果keyword为null,需要设置为空字符串"",否则查询时会拼接成 %null% , 我们期望的是 %%
            if(StringUtil.isEmpty(keyword)){
                keyword = "" ;
            }
            //将keyword保存(覆盖)到session中
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
            //此时keyword应该从session作用域获取
            String pageNoStr = request.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);   //如果从请求中读取到pageNo,则类型转换。否则,pageNo默认就是1
            }
            //如果不是点击的查询按钮,那么查询是基于session中保存的现有keyword进行查询
            Object keywordObj = session.getAttribute("keyword");
            if(keywordObj!=null){
                keyword = (String)keywordObj ;
            }else{
                keyword = "" ;
            }
        }

        // 重新更新当前页的值
        session.setAttribute("pageNo",pageNo);

        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList(keyword , pageNo);
        session.setAttribute("fruitList",fruitList);

        //总记录条数
        int fruitCount = fruitDAO.getFruitCount(keyword);
        //总页数
        int pageCount = (fruitCount+5-1)/5 ;
        /*
        总记录条数       总页数
        1               1
        5               1
        6               2
        10              2
        11              3
        fruitCount      (fruitCount+5-1)/5
         */
        session.setAttribute("pageCount",pageCount);

        //此处的视图名称是 index
        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
        //逻辑视图名称 :   index
        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
        //所以真实的视图名称是:      /       index       .html
        super.processTemplate("index",request,response);
    }
}


反射方法,这样可以增加更多的 method,而不用 switch 来增加代码

@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {
    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置编码
        request.setCharacterEncoding("UTF-8");

        String operate = request.getParameter("operate");
        if(StringUtil.isEmpty(operate)){
            operate = "index" ;
        }

        // 获取当前类中所有方法
        Method[] methods = this.getClass().getDeclareMethods();

        for (Method m : methods) {
            String methodName = m.getName();
            if (operate.equals(methodName)) {
                try {
                    // 找到和 operate 同名的方法, 那么通过反射技术调用它
                    m.invoke(this, request, response);
                    return;
                } catch(IllegalAcc....)
                e.printS
            }
        }

        throw new RuntimeException("operate值非法!");
    }

        // switch(operate){
        //     case "index":
        //         index(request,response);
        //         break;
        //     case "add":
        //         add(request,response);
        //         break;
        //     case "del":
        //         del(request,response);
        //         break;
        //     case "edit":
        //         edit(request,response);
        //         break;
        //     case "update":
        //         update(request,response);
        //         break;
        //     default:
                //  throw new RuntimeException("operate值非法!");
        // }
    }

    private void update(HttpServletRequest request, HttpServletResponse response) throws 


javaweb1

javaweb3

javaweb4

javaweb5

spring

springmvc