[Java]JavaWeb学习笔记(动力节点老杜2022)【Javaweb+MVC架构模式完结】(六)

简介: [Java]JavaWeb学习笔记(动力节点老杜2022)【Javaweb+MVC架构模式完结】(六)

🥽 在一个web应用中应该如何完成资源的跳转

  • 在一个web应用中通过两种方式,可以完成资源的跳转:
  • 第一种方式:转发
  • 第二种方式:重定向
  • 转发和重定向有什么区别?
  • 代码上有什么区别?
  • 转发
// 获取请求转发器对象
// 告诉Tomcat下一次请求要发给哪个Servlet对象
RequestDispatcher dispatcher = request.getRequestDispatcher("/dept/list");
// 调用请求转发器对象的forward方法完成转发
// 传入request, response 保证为同一次请求,保证请求域相同
dispatcher.forward(request, response);
// 合并一行代码
request.getRequestDispatcher("/dept/list").forward(request, response);
// 转发的时候是一次请求,不管你转发了多少次。都是一次请求。
// AServlet转发到BServlet,再转发到CServlet,再转发到DServlet,不管转发了多少次,都在同一个request当中。
// 这是因为调用forward方法的时候,会将当前的request和response对象传递给下一个Servlet。
  • 重定向
// 注意:路径上要加一个项目名。为什么?
// 浏览器发送请求,请求路径上是需要添加项目名的。
// 以下这一行代码会将请求路径“/oa/dept/list”发送给浏览器
// 浏览器会自发的向服务器发送一次全新的请求:/oa/dept/list
response.sendRedirect("/oa/dept/list");
  • 形式上有什么区别?
  • 转发(一次请求)
  • 在浏览器地址栏上发送的请求是:http://localhost:8080/servlet10/a ,最终请求结束之后,浏览器地址栏上的地址还是这个。没变。
  • 重定向(两次请求)
  • 在浏览器地址栏上发送的请求是:http://localhost:8080/servlet10/a ,最终在浏览器地址栏上显示的地址是:http://localhost:8080/servlet10/b
  • 转发和重定向的本质区别?
  • 转发:是由WEB服务器来控制的。A资源跳转到B资源,这个跳转动作是Tomcat服务器内部完成的。
  • 重定向:是浏览器完成的。具体跳转到哪个资源,是浏览器说了算。
  • 使用一个例子去描述这个转发和重定向
  • 借钱(转发:发送了一次请求)
  • 杜老师没钱了,找张三借钱,其实张三没有钱,但是张三够义气,张三自己找李四借了钱,然后张三把这个钱给了杜老师,杜老师不知道这个钱是李四的,杜老师只求了一个人。杜老师以为这个钱就是张三的。
  • 借钱(重定向:发送了两次请求)
  • 杜老师没钱了,找张三借钱,张三没有钱,张三有一个好哥们,叫李四,李四是个富二代,于是张三将李四的家庭住址告诉了杜老师,杜老师按照这个地址去找到李四,然后从李四那里借了钱。显然杜老师在这个过程中,求了两个人。并且杜老师知道最终这个钱是李四借给俺的。
  • 转发和重定向应该如何选择?什么时候使用转发,什么时候使用重定向?
  • 如果在上一个Servlet当中向request域当中绑定了数据,希望从下一个Servlet当中把request域里面的数据取出来,使用转发机制。
  • 剩下所有的请求均使用重定向。(重定向使用较多。)
  • 跳转的下一个资源有没有要求呢?必须是一个Servlet吗?
  • 不一定,跳转的资源只要是服务器内部合法的资源即可。包括:Servlet、JSP、HTML…
  • 转发会存在浏览器的刷新问题。由于请求转发的前端路径不会发送变化,所以前端进行刷新会重新执行一次与之前相同的请求,如果之前执行的为向数据库插入信息的请求,则使用转发每次进行刷新都会重新执行一次插入操作。使用重定向则不会,重定向是发送一次与之前请求无关的一次新请求。

🥽 将oa项目中的资源跳转修改为合适的跳转方式

删除之后,重定向

// 判断成功或失败,进行页面的跳转
if (count >= 1) {
    //删除成功
    //仍然跳转到部门列表页面
    //部门列表页面的显示需要执行另一个Servlet。怎么办?转发。
    // request.getRequestDispatcher("/dept/list").forward(request, response);
    response.sendRedirect(request.getContextPath() + "/dept/list");
} else {
    // 删除失败
    // request.getRequestDispatcher("/error.html").forward(request, response);
    response.sendRedirect(request.getContextPath() + "/error.html");
}

修改之后,重定向

// 成功或失败
if (count >= 1) {
    // request.getRequestDispatcher("/dept/list").forward(request, response);
    response.sendRedirect(request.getContextPath() + "/dept/list");
} else {
    // request.getRequestDispatcher("/error.html").forward(request, response);
    response.sendRedirect(request.getContextPath() + "/error.html");
}

保存之后,重定向

// 成功或失败
if (count >= 1) {
    // request.getRequestDispatcher("/dept/list").forward(request, response);
    response.sendRedirect(request.getContextPath() + "/dept/list");
} else {
    // request.getRequestDispatcher("/error.html").forward(request, response);
    response.sendRedirect(request.getContextPath() + "/error.html");
}

🥽 Servlet注解,简化配置

  • 分析oa项目中的web.xml文件
  • 现在只是一个单标的CRUD,没有复杂的业务逻辑,很简单的一丢丢功能。web.xml文件中就有如此多的配置信息。如果采用这种方式,对于一个大的项目来说,这样的话web.xml文件会非常庞大,有可能最终会达到几十兆。
  • 在web.xml文件中进行servlet信息的配置,显然开发效率比较低,每一个都需要配置一下。
  • 而且在web.xml文件中的配置是很少被修改的,所以这种配置信息能不能直接写到java类当中呢?可以的。
  • Servlet3.0版本之后,推出了各种Servlet基于注解式开发。优点是什么?
  • 开发效率高,不需要编写大量的配置信息。直接在java类上使用注解进行标注。
  • web.xml文件体积变小了。
  • 并不是说注解有了之后,web.xml文件就不需要了:
  • 有一些需要变化的信息,还是要配置到web.xml文件中。一般都是 注解+配置文件 的开发模式。
  • 一些不会经常变化修改的配置建议使用注解。一些可能会被修改的建议写到配置文件中。
  • 我们的第一个注解:
jakarta.servlet.annotation.WebServlet
  • 在Servlet类上使用:@WebServlet,WebServlet注解中有哪些属性呢?
  • name属性:用来指定Servlet的名字。等同于:
  • urlPatterns属性:用来指定Servlet的映射路径。可以指定多个字符串。
  • loadOnStartUp属性:用来指定在服务器启动阶段是否加载该Servlet。等同于:
  • value属性:当注解的属性名是value的时候,使用注解的时候,value属性名是可以省略的
//@WebServlet(urlPatterns = {"/welcome1", "/welcome2"})
// 注意:当注解的属性是一个数组,并且数组中只有一个元素,大括号可以省略。
//@WebServlet(urlPatterns = "/welcome")
// 这个value属性和urlPatterns属性一致,都是用来指定Servlet的映射路径的。
//@WebServlet(value = {"/welcome1", "/welcome2"})
// 如果注解的属性名是value的话,属性名也是可以省略的。
//@WebServlet(value = "/welcome1")
//@WebServlet({"/wel", "/abc", "/def"})
@WebServlet("/wel")
public class WelcomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print("欢迎学习Servlet。");
    }
}
  • 注意:不是必须将所有属性都写上,只需要提供需要的。(需要什么用什么。)
  • 注意:属性是一个数组,如果数组中只有一个元素,使用该注解的时候,属性值的大括号可以省略
package com.bjpowernode.javaweb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
@WebServlet(name = "hello",
        urlPatterns = {"/hello1", "/hello2", "/hello3"},
        loadOnStartup = 1, // 服务器部署启动时加载该类
        // 初始化参数
 initParams = {@WebInitParam(name="username", value="root"), @WebInitParam(name="password", value="123")})
public class HelloServlet extends HttpServlet {
    // 无参数构造方法
    public HelloServlet() {
        System.out.println("无参数构造方法执行,HelloServlet加载完成");
    }
    /*@WebServlet
    private String name;*/
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        // 获取Servlet Name
        String servletName = getServletName();
        out.print("servlet name = " + servletName + "<br>");
        // 获取servlet path
        String servletPath = request.getServletPath();
        out.print("servlet path = " + servletPath + "<br>");
        // 获取初始化参数
        Enumeration<String> names = getInitParameterNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            String value = getInitParameter(name);
            out.print(name + "=" + value + "<br>");
        }
    }
}
  • 注解对象的使用格式:
  • @注解名称(属性名=属性值, 属性名=属性值, 属性名=属性值…)

🥽 通过反射获取注解

public class ReflectAnnotation {
    public static void main(String[] args) throws Exception{
        // 使用反射机制将类上面的注解进行解析。
        // 获取类Class对象
        Class<?> welcomeServletClass = Class.forName("com.bjpowernode.javaweb.servlet.WelcomeServlet");
        // 获取这个类上面的注解对象
        // 先判断这个类上面有没有这个注解对象,如果有这个注解对象,就获取该注解对象。
        //boolean annotationPresent = welcomeServletClass.isAnnotationPresent(WebServlet.class);
        //System.out.println(annotationPresent);
        if (welcomeServletClass.isAnnotationPresent(WebServlet.class)) {
            // 获取这个类上面的注解对象
            WebServlet webServletAnnotation = welcomeServletClass.getAnnotation(WebServlet.class);
            // 获取注解的value属性值。
            String[] value = webServletAnnotation.value();
            for (int i = 0; i < value.length; i++) {
                System.out.println(value[i]);
            }
        }
    }
}

🥽 使用模板方法设计模式优化oa项目

  • 上面的注解解决了配置文件的问题。但是现在的oa项目仍然存在一个比较臃肿的问题。
  • 一个单标的CRUD,就写了6个Servlet。如果一个复杂的业务系统,这种开发方式,显然会导致类爆炸。(类的数量太大。)
  • 怎么解决这个类爆炸问题?可以使用模板方法设计模式。
  • 怎么解决类爆炸问题?
  • 以前的设计是一个请求一个Servlet类。1000个请求对应1000个Servlet类。导致类爆炸。
  • 可以这样做:一个请求对应一个方法。一个业务对应一个Servlet类。
  • 处理部门相关业务的对应一个DeptServlet。处理用户相关业务的对应一个UserServlet。处理银行卡卡片业务对应一个CardServlet。
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.utils.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
// 模板类
@WebServlet({"/dept/list", "/dept/save", "/dept/edit", "/dept/detail", "/dept/delete", "/dept/modify"})
// 模糊匹配
// 只要请求路径是以"/dept"开始的,都走这个Servlet。
//@WebServlet("/dept/*")
public class DeptServlet extends HttpServlet {
    // 模板方法
    // 重写service方法(并没有重写doGet或者doPost)
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取servlet path
        String servletPath = request.getServletPath();
        if("/dept/list".equals(servletPath)){
            doList(request, response);
        } else if("/dept/save".equals(servletPath)){
            doSave(request, response);
        } else if("/dept/edit".equals(servletPath)){
            doEdit(request, response);
        } else if("/dept/detail".equals(servletPath)){
            doDetail(request, response);
        } else if("/dept/delete".equals(servletPath)){
            doDel(request, response);
        } else if("/dept/modify".equals(servletPath)){
            doModify(request, response);
        }
    }
    private void doList(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取应用的根路径
        String contextPath = request.getContextPath();
        // 设置响应的内容类型以及字符集。防止中文乱码问题。
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print("<!DOCTYPE html>");
        out.print("<html>");
        out.print(" <head>");
        out.print("   <meta charset='utf-8'>");
        out.print("   <title>部门列表页面</title>");
        out.print("<script type='text/javascript'>");
        out.print("    function del(dno){");
        out.print("        if(window.confirm('亲,删了不可恢复哦!')){");
        out.print("            document.location.href = '"+contextPath+"/dept/delete?deptno=' + dno");
        out.print("        }");
        out.print("    }");
        out.print("</script>");
        out.print(" </head>");
        out.print(" <body>");
        out.print("   <h1 align='center'>部门列表</h1>");
        out.print("   <hr >");
        out.print("   <table border='1px' align='center' width='50%'>");
        out.print("     <tr>");
        out.print("       <th>序号</th>");
        out.print("       <th>部门编号</th>");
        out.print("       <th>部门名称</th>");
        out.print("       <th>操作</th>");
        out.print("     </tr>");
        /*上面一部分是死的*/
        // 连接数据库,查询所有的部门
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 获取连接
            conn = DBUtil.getConnection();
            // 获取预编译的数据库操作对象
            String sql = "select deptno as a,dname,loc from dept";
            ps = conn.prepareStatement(sql);
            // 执行SQL语句
            rs = ps.executeQuery();
            // 处理结果集
            int i = 0;
            while(rs.next()){
                String deptno = rs.getString("a");
                String dname = rs.getString("dname");
                String loc = rs.getString("loc");
                out.print("     <tr>");
                out.print("       <td>"+(++i)+"</td>");
                out.print("       <td>"+deptno+"</td>");
                out.print("       <td>"+dname+"</td>");
                out.print("       <td>");
                out.print("         <a href='javascript:void(0)' οnclick='del("+deptno+")'>删除</a>");
                out.print("         <a href='"+contextPath+"/dept/edit?deptno="+deptno+"'>修改</a>");
                out.print("         <a href='"+contextPath+"/dept/detail?fdsafdsas="+deptno+"'>详情</a>");
                out.print("       </td>");
                out.print("     </tr>");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            DBUtil.close(conn, ps, rs);
        }
        /*下面一部分是死的*/
        out.print("   </table>");
        out.print("   <hr >");
        out.print("   <a href='"+contextPath+"/add.html'>新增部门</a>");
        out.print(" </body>");
        out.print("</html>");
    }
    private void doSave(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取部门的信息
        // 注意乱码问题(Tomcat10不会出现这个问题)
        request.setCharacterEncoding("UTF-8");
        String deptno = request.getParameter("deptno");
        String dname = request.getParameter("dname");
        String loc = request.getParameter("loc");
        // 连接数据库执行insert语句
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            String sql = "insert into dept(deptno, dname, loc) values(?,?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1, deptno);
            ps.setString(2, dname);
            ps.setString(3, loc);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        if (count == 1) {
            // 保存成功跳转到列表页面
            // 转发是一次请求。
            //request.getRequestDispatcher("/dept/list").forward(request, response);
            // 这里最好使用重定向(浏览器会发一次全新的请求。)
            // 浏览器在地址栏上发送请求,这个请求是get请求。
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }else{
            // 保存失败跳转到错误页面
            //request.getRequestDispatcher("/error.html").forward(request, response);
            // 这里也建议使用重定向。
            response.sendRedirect(request.getContextPath() + "/error.html");
        }
    }
    private void doEdit(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取应用的根路径。
        String contextPath = request.getContextPath();
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print("<!DOCTYPE html>");
        out.print("<html>");
        out.print(" <head>");
        out.print("   <meta charset='utf-8'>");
        out.print("   <title>修改部门</title>");
        out.print(" </head>");
        out.print(" <body>");
        out.print("   <h1>修改部门</h1>");
        out.print("   <hr >");
        out.print("   <form action='"+contextPath+"/dept/modify' method='post'>");
        // 获取部门编号
        String deptno = request.getParameter("deptno");
        // 连接数据库,根据部门编号查询部门的信息。
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = DBUtil.getConnection();
            String sql = "select dname, loc as location from dept where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, deptno);
            rs = ps.executeQuery();
            // 这个结果集中只有一条记录。
            if(rs.next()){
                String dname = rs.getString("dname");
                String location = rs.getString("location"); // 参数"location"是sql语句查询结果列的列名。
                // 输出动态网页。
                out.print("                部门编号<input type='text' name='deptno' value='"+deptno+"' readonly /><br>");
                out.print("                部门名称<input type='text' name='dname' value='"+dname+"'/><br>");
                out.print("                部门位置<input type='text' name='loc' value='"+location+"'/><br>");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, rs);
        }
        out.print("     <input type='submit' value='修改'/><br>");
        out.print("   </form>");
        out.print(" </body>");
        out.print("</html>");
    }
    private void doDetail(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print("<!DOCTYPE html>");
        out.print("<html>");
        out.print(" <head>");
        out.print("   <meta charset='utf-8'>");
        out.print("   <title>部门详情</title>");
        out.print(" </head>");
        out.print(" <body>");
        out.print("   <h1>部门详情</h1>");
        out.print("   <hr >");
        // 获取部门编号
        // /oa/dept/detail?fdsafdsas=30
        // 虽然是提交的30,但是服务器获取的是"30"这个字符串。
        String deptno = request.getParameter("fdsafdsas");
        // 连接数据库,根据部门编号查询部门信息。
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = DBUtil.getConnection();
            String sql = "select dname,loc from dept where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, deptno);
            rs = ps.executeQuery();
            // 这个结果集一定只有一条记录。
            if(rs.next()){
                String dname = rs.getString("dname");
                String loc = rs.getString("loc");
                out.print("部门编号:"+deptno+" <br>");
                out.print("部门名称:"+dname+"<br>");
                out.print("部门位置:"+loc+"<br>");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, rs);
        }
        out.print("   <input type='button' value='后退' οnclick='window.history.back()'/>");
        out.print(" </body>");
        out.print("</html>");
    }
    private void doDel(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 根据部门编号,删除部门。
        // 获取部门编号
        String deptno = request.getParameter("deptno");
        // 连接数据库删除数据
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            // 开启事务(自动提交机制关闭)
            conn.setAutoCommit(false);
            String sql = "delete from dept where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, deptno);
            // 返回值是:影响了数据库表当中多少条记录。
            count = ps.executeUpdate();
            // 事务提交
            conn.commit();
        } catch (SQLException e) {
            // 遇到异常要回滚
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        // 判断删除成功了还是失败了。
        if (count == 1) {
            //删除成功
            //仍然跳转到部门列表页面
            //部门列表页面的显示需要执行另一个Servlet。怎么办?转发。
            //request.getRequestDispatcher("/dept/list").forward(request, response);
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }else{
            // 删除失败
            //request.getRequestDispatcher("/error.html").forward(request, response);
            response.sendRedirect(request.getContextPath() + "/error.html");
        }
    }
    private void doModify(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 解决请求体的中文乱码问题。
        request.setCharacterEncoding("UTF-8");
        // 获取表单中的数据
        String deptno = request.getParameter("deptno");
        String dname = request.getParameter("dname");
        String loc = request.getParameter("loc");
        // 连接数据库执行更新语句
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            String sql = "update dept set dname = ?, loc = ? where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, dname);
            ps.setString(2, loc);
            ps.setString(3, deptno);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        if (count == 1) {
            // 更新成功
            // 跳转到部门列表页面(部门列表页面是通过Java程序动态生成的,所以还需要再次执行另一个Servlet)
            //request.getRequestDispatcher("/dept/list").forward(request, response);
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }else{
            // 更新失败
            //request.getRequestDispatcher("/error.html").forward(request, response);
            response.sendRedirect(request.getContextPath() + "/error.html");
        }
    }
}

🥽 分析使用纯粹Servlet开发web应用的缺陷

  • 在Servlet当中编写HTML/CSS/JavaScript等前端代码。存在什么问题?
  • java程序中编写前端代码,编写难度大。麻烦。
  • java程序中编写前端代码,显然程序的耦合度非常高。
  • java程序中编写前端代码,代码非常不美观。
  • java程序中编写前端代码,维护成本太高。(非常难于维护)
  • 修改小小的一个前端代码,只要有改动,就需要重新编译java代码,生成新的class文件,打一个新的war包,重新发布。
  • 思考一下,如果是你的话,你准备怎么解决这个问题?
  • 思路很重要。使用什么样的思路去做、去解决这个问题
  • 上面的那个Servlet(Java程序)能不能不写了,让机器自动生成。我们程序员只需要写这个Servlet程序中的“前端的那段代码”,然后让机器将我们写的“前端代码”自动翻译生成“Servlet这种java程序”。然后机器再自动将“java”程序编译生成"class"文件。然后再使用JVM调用这个class中的方法。

🥽 JSP

🌊 我的第一个JSP程序

  • 在WEB-INF目录之外创建一个index.jsp文件,然后这个文件中没有任何内容。

  • 将上面的项目部署之后,启动服务器,打开浏览器,访问以下地址:
  • http://localhost:8080/jsp/index.jsp 展现在大家面前的是一个空白。
  • 实际上访问以上的这个:index.jsp,底层执行的是:index_jsp.class 这个java程序。
  • 这个index.jsp会被tomcat翻译生成index_jsp.java文件,然后tomcat服务器又会将index_jsp.java编译生成index_jsp.class文件
  • 访问index.jsp,实际上执行的是index_jsp.class中的方法。

🌊 JSP概述

  • JSP实际上就是一个Servlet。
  • index.jsp访问的时候,会自动翻译生成index_jsp.java,会自动编译生成index_jsp.class,那么index_jsp 这就是一个类。
  • index_jsp 类继承 HttpJspBase,而HttpJspBase类继承的是HttpServlet。所以index_jsp类就是一个Servlet类。
  • jsp的生命周期和Servlet的生命周期完全相同。完全就是一个东西。没有任何区别。
  • jsp和servlet一样,都是单例的。(假单例。)
  • jsp文件第一次访问的时候是比较慢的,为什么?
  • 为什么大部分的运维人员在给客户演示项目的时候,为什么提前先把所有的jsp文件先访问一遍。
  • 第一次比较麻烦:
  • 要把jsp文件翻译生成java源文件
  • java源文件要编译生成class字节码文件
  • 然后通过class去创建servlet对象
  • 然后调用servlet对象的init方法
  • 最后调用servlet对象的service方法。
  • 第二次就比较快了,为什么?
  • 因为第二次直接调用单例servlet对象的service方法即可。
  • JSP是什么?
  • JSP是java程序。(JSP本质还是一个Servlet)
  • JSP是:JavaServer Pages的缩写。(基于Java语言实现的服务器端的页面。)
  • Servlet是JavaEE的13个子规范之一,那么JSP也是JavaEE的13个子规范之一。
  • JSP是一套规范。所有的web容器/web服务器都是遵循这套规范的,都是按照这套规范进行的“翻译”
  • 每一个web容器/web服务器都会内置一个JSP翻译引擎。
  • 对JSP进行错误调试的时候,还是要直接打开JSP文件对应的java文件,检查java代码。
  • 开发JSP的最高境界:
  • 眼前是JSP代码,但是脑袋中呈现的是java代码。
  • JSP既然本质上是一个Servlet,那么JSP和Servlet到底有什么区别呢?
  • 职责不同:
  • Servlet的职责是什么:收集数据。(Servlet的强项是逻辑处理,业务处理,然后链接数据库,获取/收集数据。)
  • JSP的职责是什么:展示数据。(JSP的强项是做数据的展示)

🌊 JSP的基础语法

💦 JSP中直接编写文字

  • 在jsp文件中直接编写文字,都会自动被翻译到哪里?
  • 翻译到servlet类的service方法的out.write(“翻译到这里”),直接翻译到双引号里,被java程序当做普通字符串打印输出到浏览器。
  • 在JSP中编写的HTML CSS JS代码,这些代码对于JSP来说只是一个普通的字符串。但是JSP把这个普通的字符串一旦输出到浏览器,浏览器就会对HTML CSS JS进行解释执行。展现一个效果。

💦 JSP的page指令

  • JSP的page指令(这个指令后面再详细说,这里先解决一下中文乱码问题,写在文件内容开始位置),解决响应时的中文乱码问题:
  • 通过page指令来设置响应的内容类型,在内容类型的最后面添加:charset=UTF-8
  • <%@page contentType=“text/html;charset=UTF-8”%>,表示响应的内容类型是text/html,采用的字符集UTF-8
  • <%@page import=“java.util.List,java.util.ArrayList”%>

💦 JSP中编写java程序

💧 <% java语句; %>

<%
  System.out.println("hello JSP");
%>

  • 脚本块
  • 在这个符号当中编写的被视为java程序,被翻译到Servlet类的service方法内部。
  • 这里你要细心点,你要思考,在<% %>这个符号里面写java代码的时候,你要时时刻刻的记住你正在“方法体”当中写代码,方法体中可以写什么,不可以写什么,你心里是否明白呢?
  • 在service方法当中编写的代码是有顺序的,方法体当中的代码要遵循自上而下的顺序依次逐行执行。
  • service方法当中不能写静态代码块,不能写方法,不能定义成员变量。。。。。。
  • 在同一个JSP当中 <%%> 这个符号可以出现多个。

💧 <%! %>

  • 可以进行成员变量、静态代码块的声明
  • 在这个符号当中编写的java程序会自动翻译到service方法之外。
  • 这个语法很少用,为什么?不建议使用,因为在service方法外面写静态变量和实例变量,都会存在线程安全问题,因为JSP就是servlet,servlet是单例的,多线程并发的环境下,这个静态变量和实例变量一旦有修改操作,必然会存在线程安全问题。

💧 JSP的输出语句 <%= %>

  • 怎么向浏览器上输出一个java变量。
  • <% String name = “jack”; out.write("name = " + name); %>
  • 注意:以上代码中的out是JSP的九大内置对象之一。可以直接拿来用。当然,必须只能在service方法内部使用。
  • 九大内置对象只能在service方法中使用
  • 如果向浏览器上输出的内容中没有“java代码”,例如输出的字符串是一个固定的字符串,可以直接在jsp中编写,不需要写到<%%> 这里。
  • 如果输出的内容中含有“java代码”,这个时候可以使用以下语法格式:
  • <%= %> 注意:在=的后面编写要输出的内容。
  • <%= %> 这个符号会被翻译到哪里?最终翻译成什么?
  • 翻译成了这个java代码: out.print();
  • 翻译到service方法当中了。
<%="hello world"%>

  • 什么时候使用<%=%> 输出呢?输出的内容中含有java的变量,输出的内容是一个动态的内容,不是一个死的字符串。如果输出的是一个固定的字符串,直接在JSP文件中编写即可。

💦 JSP中的注释

  • 在JSP中如何编写JSP的专业注释
  • <%--JSP的专业注释,不会被翻译到java源代码当中。--%>
  • <!--这种注释属于HTML的注释,这个注释信息仍然会被翻译到java源代码当中,不建议。-->

💦 JSP基础语法总结

  • JSP基础语法总结:
  • JSP中直接编写普通字符串
  • 翻译到service方法的out.write(“这里”)
  • <%%>
  • 翻译到service方法体内部,里面是一条一条的java语句。
  • <%! %>
  • 翻译到service方法之外。
  • <%= %>
  • 翻译到service方法体内部,翻译为:out.print();
  • <%@page contentType=“text/html;charset=UTF-8”%>
  • page指令,通过contentType属性用来设置响应的内容类型。

🥽 使用Servlet + JSP完成oa项目的改造

  • 使用Servlet处理业务,收集数据。 使用JSP展示数据。
  • 将之前原型中的html文件,全部修改为jsp,然后在jsp文件头部添加page指令(指定contentType防止中文乱码),将所有的JSP直接拷贝到web目录下。
  • 完成所有页面的正常流转。(页面仍然能够正常的跳转。修改超链接的请求路径。)
  • <%=request.getContextPath() %> 在JSP中动态的获取应用的根路径。
  • Servlet中连接数据库,查询所有的部门,遍历结果集。
  • 遍历结果集的过程中,取出部门编号、部门名、位置等信息,封装成java对象。
  • 将java对象存放到List集合中。
  • 将List集合存储到request域当中。
  • 转发forward到jsp。
  • 在JSP中:
  • 从request域当中取出List集合。
  • 遍历List集合,取出每个部门对象。动态生成tr。
  • 思考一个问题:如果我只用JSP这一个技术,能不能开发web应用?
  • 当然可以使用JSP来完成所有的功能。因为JSP就是Servlet,在JSP的<%%>里面写的代码就是在service方法当中的,所以在<%%>当中完全可以编写JDBC代码,连接数据库,查询数据,也可以在这个方法当中编写业务逻辑代码,处理业务,都是可以的,所以使用单独的JSP开发web应用完全没问题。
  • 虽然JSP一个技术就可以完成web应用,但是不建议,还是建议采用servlet + jsp的方式进行开发。这样都能将各自的优点发挥出来。JSP就是做数据展示。Servlet就是做数据的收集。(JSP中编写的Java代码越少越好。)一定要职责分明。
  • JSP文件的扩展名必须是xxx.jsp吗?
  • jsp文件的扩展名是可以配置的。不是固定的。
  • 在CATALINA_HOME/conf/web.xml,在这个文件当中配置jsp文件的扩展名。
<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>
  • xxx.jsp文件对于小猫咪来说,只是一个普通的文本文件,web容器会将xxx.jsp文件最终生成java程序,最终调用的是java对象相关的方法,真正执行的时候,和jsp文件就没有关系了。
  • 小窍门:JSP如果看不懂,建议把jsp翻译成java代码,就能看懂了。
  • 同学问:包名bean是什么意思?
  • javabean(java的logo是一杯冒着热气的咖啡。javabean被翻译为:咖啡豆)
  • java是一杯咖啡,咖啡又是由一粒一粒的咖啡豆研磨而成。
  • 整个java程序中有很多bean的存在。由很多bean组成。
  • 什么是javabean?实际上javabean你可以理解为符合某种规范的java类,比如:
  • 有无参数构造方法
  • 属性私有化
  • 对外提供公开的set和get方法
  • 实现java.io.Serializable接口
  • 重写toString
  • 重写hashCode+equals
  • javabean其实就是java中的实体类。负责数据的封装。
  • 由于javabean符合javabean规范,具有更强的通用性。
  • 完成剩下所有功能的改造。

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>欢迎使用OA系统</title>
</head>
<body>
<a href="<%= request.getContextPath() %>/dept/list">查看部门列表</a>
</body>
</html>

list.jsp

<%@ page import="java.util.ArrayList" %>
<%@ page import="cw.javaweb.bean.Dept" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    Object deptList =  request.getAttribute("deptList");
    ArrayList<Dept> depts = (ArrayList<Dept>) deptList;
%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>部门列表页面</title>
</head>
<body>
<h1 align="center">部门列表</h1>
<hr>
<table align="center" border="1px solid black" width="50%">
    <thead>
    <tr>
        <th>序号</th>
        <th>部门编号</th>
        <th>部门名称</th>
        <th>操作</th>
    </tr>
    </thead>
    <tbody>
    <%
        for (int i=0; i<depts.size(); i++) {
            Dept dept = depts.get(i);
    %>
        <tr>
            <td><%= (i+1) %></td>
            <td><%= dept.getDeptno()%></td>
            <td><%= dept.getDname()%></td>
            <td>
                <a href="javascript:void(0)" onclick="del(<%= dept.getDeptno() %>)" >删除</a>
                <%-- 由于修改和详情页面只是页面显示不同,数据的查询逻辑类似,所以数据的查询使用相同的逻辑 --%>
                <a href="<%= request.getContextPath() %>/dept/detail?f=m&deptno=<%= dept.getDeptno() %>">修改</a>
                <a href="<%= request.getContextPath() %>/dept/detail?f=d&deptno=<%= dept.getDeptno() %>">详情</a>
            </td>
        </tr>
    <%
        }
    %>
    </tbody>
</table>
<hr>
<a href="<%= request.getContextPath() %>/add.jsp">新增部门</a>
</body>
<script type="text/javascript">
    function del(dno){
        if(window.confirm("亲,删了不可恢复哦!")){
            document.location.href = "/oa/dept/delete?deptno=" + dno;
        }
    }
</script>
</html>

add.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>新增部门</title>
</head>
<body>
<h1>新增部门</h1>
<hr>
<form action="<%= request.getContextPath() %>/dept/add" method="post">
    部门编号:<input type="text" name="deptno"><br>
    部门名称:<input type="text" name="dname"><br>
    部门位置:<input type="text" name="loc"><br>
    <input type="submit" value="新增">
</form>
</body>
</html>

detail.jsp

<%@ page import="cw.javaweb.bean.Dept" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    Dept dept = (Dept) request.getAttribute("dept");
%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>部门详情</title>
</head>
<body>
<h1>部门详情</h1>
<hr>
<p>部门编号:<%= dept.getDeptno() %></p>
<p>部门名称:<%= dept.getDname() %></p>
<p>部门位置:<%= dept.getLoc() %></p>
<input type="button" value="后退" onclick="window.history.back()">
</body>
</html>

edit.jsp

<%@ page import="cw.javaweb.bean.Dept" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    Dept dept = (Dept) request.getAttribute("dept");
%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>修改部门</title>
</head>
<body>
<h1>修改部门</h1>
<hr >
<form action="<%= request.getContextPath() %>/dept/modify" method="get">
    <!-- 部门编号不允许修改 -->
    部门编号<input type="text" name="deptno" value="<%= dept.getDeptno() %>" readonly /><br>
    部门名称<input type="text" name="dname" value="<%= dept.getDname() %>"/><br>
    部门位置<input type="text" name="loc" value="<%= dept.getLoc() %>"/><br>
    <input type="submit" value="修改"/><br>
</form>
</body>
</html>

Dept.java

package cw.javaweb.bean;
public class Dept {
    private String deptno;
    private String dname;
    private String loc;
    public Dept() {
    }
    public Dept(String deptno, String dname, String loc) {
        this.deptno = deptno;
        this.dname = dname;
        this.loc = loc;
    }
    public String getDeptno() {
        return deptno;
    }
    public void setDeptno(String deptno) {
        this.deptno = deptno;
    }
    public String getDname() {
        return dname;
    }
    public void setDname(String dname) {
        this.dname = dname;
    }
    public String getLoc() {
        return loc;
    }
    public void setLoc(String loc) {
        this.loc = loc;
    }
    @Override
    public String toString() {
        return "Dept{" + "deptno='" + deptno + '\'' + ", dname='" + dname + '\'' + ", loc='" + loc + '\'' + '}';
    }
}

DeptServlet.java

package cw.javaweb.oa.action;
import cw.javaweb.bean.Dept;
import cw.javaweb.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
@WebServlet({"/dept/list", "/dept/detail", "/dept/modify", "/dept/delete", "/dept/add"})
public class DeptServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取servlet路径
        String servletPath = request.getServletPath();
        if ("/dept/list".equals(servletPath)) {
            doList(request, response);
        } else if ("/dept/detail".equals(servletPath)) {
            doDetail(request, response);
        } else if ("/dept/modify".equals(servletPath)) {
            doModify(request, response);
        } else if ("/dept/delete".equals(servletPath)) {
            doDel(request, response);
        } else if ("/dept/add".equals(servletPath)) {
            doAdd(request, response);
        }
    }
    private void doAdd(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取部门的信息
        // 注意乱码问题(Tomcat10不会出现这个问题)
        request.setCharacterEncoding("UTF-8");
        String deptno = request.getParameter("deptno");
        String dname = request.getParameter("dname");
        String loc = request.getParameter("loc");
        // 连接数据库执行insert语句
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            String sql = "insert into dept(deptno, dname, loc) values(?,?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1, deptno);
            ps.setString(2, dname);
            ps.setString(3, loc);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        if (count == 1) {
            // 保存成功跳转到列表页面
            // 转发是一次请求。
            //request.getRequestDispatcher("/dept/list").forward(request, response);
            // 这里最好使用重定向(浏览器会发一次全新的请求。)
            // 浏览器在地址栏上发送请求,这个请求是get请求。
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }else{
            // 保存失败跳转到错误页面
            //request.getRequestDispatcher("/error.html").forward(request, response);
            // 这里也建议使用重定向。
            response.sendRedirect(request.getContextPath() + "/error.html");
        }
    }
    private void doDel(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 根据部门编号,删除部门。
        // 获取部门编号
        String deptno = request.getParameter("deptno");
        // 连接数据库删除数据
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            // 开启事务(自动提交机制关闭)
            conn.setAutoCommit(false);
            String sql = "delete from dept where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, deptno);
            // 返回值是:影响了数据库表当中多少条记录。
            count = ps.executeUpdate();
            // 事务提交
            conn.commit();
        } catch (SQLException e) {
            // 遇到异常要回滚
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        // 判断删除成功了还是失败了。
        if (count == 1) {
            //删除成功
            //仍然跳转到部门列表页面
            //部门列表页面的显示需要执行另一个Servlet。怎么办?转发。
            //request.getRequestDispatcher("/dept/list").forward(request, response);
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }else{
            // 删除失败
            //request.getRequestDispatcher("/error.html").forward(request, response);
            response.sendRedirect(request.getContextPath() + "/error.html");
        }
    }
    private void doModify(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 解决请求体的中文乱码问题。
        request.setCharacterEncoding("UTF-8");
        // 获取表单中的数据
        String deptno = request.getParameter("deptno");
        String dname = request.getParameter("dname");
        String loc = request.getParameter("loc");
        // 连接数据库执行更新语句
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            String sql = "update dept set dname = ?, loc = ? where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, dname);
            ps.setString(2, loc);
            ps.setString(3, deptno);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        if (count == 1) {
            // 更新成功
            // 跳转到部门列表页面(部门列表页面是通过Java程序动态生成的,所以还需要再次执行另一个Servlet)
            //request.getRequestDispatcher("/dept/list").forward(request, response);
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }else{
            // 更新失败
            //request.getRequestDispatcher("/error.html").forward(request, response);
            response.sendRedirect(request.getContextPath() + "/error.html");
        }
    }
    private void doDetail(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        // 获取部门编号
        String deptno = request.getParameter("deptno");
        // 连接数据库,根据部门编号查询部门信息。
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = DBUtil.getConnection();
            String sql = "select dname,loc from dept where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, deptno);
            rs = ps.executeQuery();
            // 这个结果集一定只有一条记录。
            if(rs.next()){
                String dname = rs.getString("dname");
                String loc = rs.getString("loc");
                Dept dept = new Dept(deptno, dname, loc);
                request.setAttribute("dept", dept);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, rs);
        }
        // 获取是修改还是查看详情
        String f = request.getParameter("f");
        if ("m".equals(f)) {
            request.getRequestDispatcher("/edit.jsp").forward(request, response);
        } else {
            request.getRequestDispatcher("/detail.jsp").forward(request, response);
        }
    }
    private void doList(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 连接数据库,查询所有的部门
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        ArrayList<Dept> depts = new ArrayList<Dept>();
        try {
            // 获取连接
            conn = DBUtil.getConnection();
            // 获取预编译的数据库操作对象
            String sql = "select deptno as a,dname,loc from dept";
            ps = conn.prepareStatement(sql);
            // 执行SQL语句
            rs = ps.executeQuery();
            // 处理结果集
            int i = 0;
            while(rs.next()){
                String deptno = rs.getString("a");
                String dname = rs.getString("dname");
                String loc = rs.getString("loc");
                Dept dept = new Dept(deptno, dname, loc);
                depts.add(dept);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            DBUtil.close(conn, ps, rs);
        }
        request.setAttribute("deptList", depts);
        request.getRequestDispatcher("/list.jsp").forward(request, response);
    }
}


相关文章
|
6月前
|
设计模式 存储 前端开发
MVVM、MVC、MVP三种常见软件架构设计模式的区别
MVC、MVP 和 MVVM 是三种常见的软件架构设计模式,主要通过分离关注点的方式来组织代码结构,优化开发效率。
148 12
|
1月前
|
存储 前端开发 调度
Flux 与传统的 MVC 架构模式区别
Flux是一种用于构建用户界面的架构模式,与传统的MVC架构不同,它采用单向数据流,通过Dispatcher统一管理数据的分发,Store负责存储数据和业务逻辑,View只负责展示数据,使得应用状态更加可预测和易于维护。
|
4月前
|
设计模式 前端开发 数据库
哇塞!Rails 的 MVC 架构也太牛了吧!快来看看这令人惊叹的编程魔法,开启新世界大门!
【8月更文挑战第31天】《Rails中的MVC架构解析》介绍了Ruby on Rails框架核心的MVC设计模式,通过模型(Model)、视图(View)和控制器(Controller)三部分分离应用逻辑,利用Active Record进行数据库操作,ERB模板渲染视图,以及控制器处理用户请求与业务逻辑,使代码更易维护和扩展,提升团队开发效率。
84 0
|
1月前
|
存储 前端开发 数据可视化
在实际项目中,如何选择使用 Flux 架构或传统的 MVC 架构
在实际项目中选择使用Flux架构或传统MVC架构时,需考虑项目复杂度、团队熟悉度和性能需求。Flux适合大型、高并发应用,MVC则适用于中小型、逻辑简单的项目。
|
3月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
497 37
|
6月前
|
存储 负载均衡 网络协议
杨老师课堂之JavaWeb项目架构之NFS文件服务器
杨老师课堂之JavaWeb项目架构之NFS文件服务器
53 0
|
3月前
|
设计模式 前端开发 数据库
理解mvc架构
mvc架构
36 4
|
4月前
|
设计模式 存储 前端开发
MVC革命:如何用一个设计模式重塑你的应用架构,让代码重构变得戏剧性地简单!
【8月更文挑战第22天】自定义MVC(Model-View-Controller)设计模式将应用分为模型、视图和控制器三个核心组件,实现关注点分离,提升代码可维护性和扩展性。模型管理数据和业务逻辑,视图负责数据显示与用户交互,控制器处理用户输入并协调模型与视图。通过示例代码展示了基本的MVC框架实现,可根据需求扩展定制。MVC模式灵活性强,支持单元测试与多人协作,但需注意避免控制器过度复杂化。
48 1
|
4月前
|
开发者 前端开发 Java
架构模式的诗与远方:如何在MVC的田野上,用Struts 2编织Web开发的新篇章
【8月更文挑战第31天】架构模式是软件开发的核心概念,MVC(Model-View-Controller)通过清晰的分层和职责分离,成为广泛采用的模式。随着业务需求的复杂化,Struts 2框架应运而生,继承MVC优点并引入更多功能。本文探讨从MVC到Struts 2的演进,强调架构模式的重要性。MVC将应用程序分为模型、视图和控制器三部分,提高模块化和可维护性。
50 0
|
4月前
|
Java 前端开发 Apache
Apache Wicket与Spring MVC等Java Web框架大PK,究竟谁才是你的最佳拍档?点击揭秘!
【8月更文挑战第31天】在Java Web开发领域,众多框架各具特色。Apache Wicket以组件化开发和易用性脱颖而出,提高了代码的可维护性和可读性。相比之下,Spring MVC拥有强大的生态系统,但学习曲线较陡;JSF与Java EE紧密集成,但在性能和灵活性上略逊一筹;Struts2虽成熟,但在RESTful API支持上不足。选择框架时还需考虑社区支持和文档完善程度。希望本文能帮助开发者找到最适合自己的框架。
55 0