Tomcat的自定义与使用

目录

1.自定义Tomcat

1.1 创建日志对象

1.2 创建自定义服务器类HttpServer

1.3 创建处理请求类

1.4 创建初始化并获取端口号的类

1.5 创建响应登录的类,并配置对应的xml文件。

1.6 创建解析xml文件的类

1.7 创建带响应和请求参数的接口

1.8 创建缓冲池

1.9 创建服务器响应接口和实现该接口的类

1.10 创建处理请求的接口

1.11 创建处理用户输入表单的信息

1.12 创建处理需求类,实现需求接口

2.Tomcat的使用

2.1 创建实现Servlet接口的实现类

2.2 创建继承HttpServlet父类的子类

2.3 直接在空项目模块中创建Servlet

3.总结

4.建议采纳


1.自定义Tomcat

1.1 创建日志对象

创建lib文件夹,导入dom4j-1.1.jar包和log4j-1.2.12.jar包,创建日志工具类MyLogger

public class MyLogger {

    private static Logger logger =Logger.getLogger(MyLogger.class);

    public static void log(String msg){
        logger.info(msg);
    }
}

1.2 创建自定义服务器类HttpServer

在类中创建开启服务器方法,在方法中实现服务器的开启,接着用while(true)循环实现不中断地使用服务器,且在方法中实现多线程的开启。

public class HttpServer {

    public static void main(String[] args) throws DocumentException {

        start();
    }

    public static void start() throws DocumentException {
        ServerSocket serverSocket = null;
        int port = ServerParse.getPort();
        try {
            serverSocket = new ServerSocket(port);
            MyLogger.log("服务器已启动");
            while (true){
                Socket client = serverSocket.accept();
                System.out.println("连接成功");
                //启动线程
                new Thread(new RequestHandler(client)).start();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            if(serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

1.3 创建处理请求类

在类中创建带客户端参数的构造函数,在类中创建实现多线程的run()方法,判断请求是否成功,成功,输出响应200页面;否则,输出404错误页面。

public class RequestHandler implements Runnable{
    private Socket client;
    public RequestHandler(Socket client){
        this.client = client;
    }
    @Override
    public void run() {
        BufferedReader reader = null;
        PrintWriter writer = null;
        try {
            MyLogger.log("当前线程" + Thread.currentThread().getName());
            reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
            writer = new PrintWriter(client.getOutputStream());
            String requestLine = reader.readLine();
            String responseURI = requestLine.split(" ")[1];
            if(responseURI.endsWith("html") || responseURI.endsWith("htm")){
                responseStaticPage(responseURI,writer);
            }else{
                String servletPath = responseURI;
                ResponseObj responseObj = new ResponseObj();
                responseObj.setWrite(writer);
                RequestObj requestObj = new RequestObj(servletPath);
                if(servletPath.contains("?")){
                    servletPath = servletPath.split("[?]")[0];
                }
                if(servletPath.split("/").length >0 && servletPath.indexOf("favicon.ico") == -1){
                    String webAppName = servletPath.split("/")[1];
                    Map<String, String> servletMap = WebParse.parse(webAppName);
                    String urlParttern = servletPath.substring(1 + webAppName.length());
                    String servletClass = servletMap.get(urlParttern);
                    if(servletClass != null){
                        //通过Class去缓冲池获取servlet
                        Servlet servlet = ServletCache.get(servletClass);
                        if(servlet == null){
                            Class aClass = Class.forName(servletClass);
                            servlet = (Servlet) aClass.newInstance();
                            ServletCache.put(servletClass,servlet);
                        }
                        servlet.service(responseObj,requestObj);
                    }
                }

            }
 writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(client != null){
                try {
                    client.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(writer !=null){
                writer.close();
            }
        }
    }

    private void responseStaticPage(String responseURI, PrintWriter writer) {

        String htmlPath = responseURI.substring(1);
        try {
            BufferedReader reader = new BufferedReader(new FileReader(htmlPath));
            StringBuilder sb = new StringBuilder();
            sb.append("HTTP/1.1 200 ok\n");
            sb.append("Content-type:text/html;charset=utf-8\n\n");
            String str = null;
            while ((str = reader.readLine()) != null){
                sb.append(str);
            }
            writer.print(sb);
        } catch (FileNotFoundException e) {
            StringBuilder sb = new StringBuilder();
            sb.append("HTTP/1.1 404 NotFound\n");
            sb.append("Content-type:text/html;charset=utf-8\n\n");
            sb.append("<html>");
            sb.append("<head><meta content='text.html;charset=utf-8'></head>");
            sb.append("<body><h1>404错误</h1></body>");
            sb.append("</html>");
            writer.print(sb);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1.4 创建初始化并获取端口号的类

初始化端口号为8080,通过读取本地文件获取端口号。

public class ServerParse {

    public static int getPort() throws DocumentException {
        Integer port = 8080;
        //创建解析器
        SAXReader reader = new SAXReader();
        Document document = reader.read("./conf/server.xml");
        Element connectorEl = (Element) document.selectSingleNode("//connector");
        port = Integer.valueOf(connectorEl.attributeValue("port"));
        return port;
    }
}

1.5 创建响应登录的类,并配置对应的xml文件。

public class LoginServlet implements Servlet {


    @Override
    public void service(ServletResponse response, ServletRequest request) {
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.1 200 ok\n");
        sb.append("Content-type:text/html;charset=utf-8\n\n");
        sb.append("<html>");
        sb.append("<head><meta content='text/html;charset=utf-8' /></head>");
        sb.append("<body><h1>正在校验登录,请稍后.......</h1></body>");
        sb.append("</html>");
        PrintWriter write = response.getWrite();
        write.print(sb);
    }
}

1.6 创建解析xml文件的类

创建解析xml文件的方法,解析xml的子元素,以键值对的方式存入map集合中,并返回map集合。

public class WebParse {

    public static void main(String[] args) throws DocumentException {
        Map<String, String> map = parse("oa");
        Set<Map.Entry<String,String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry.getKey() + ":::" + entry.getValue());
        }
    }

    public static Map<String,String> parse(String webAppName) throws DocumentException {
        webAppName = webAppName + "/WEB-INF/web.xml";
        SAXReader reader = new SAXReader();
        Document document = reader.read(webAppName);
        List<Element> servletEl = document.selectNodes("/web-app/servlet");
        Map<String,String> servletMapInfo = new HashMap<>();
        for (Element el:servletEl) {
            Element servletNameEl = (Element) el.selectSingleNode("servlet-name");
            Element servletClassEl = (Element) el.selectSingleNode("servlet-class");
            String servletName = servletNameEl.getStringValue();
            String servletClass = servletClassEl.getStringValue();
            servletMapInfo.put(servletName,servletClass);
        }
        List<Element> servletMappingEl = document.selectNodes("/web-app/servlet-mapping");
        Map<String,String> servletMappingInfo = new HashMap<>();
        for(Element el:servletMappingEl){
            Element servletNameEl = (Element) el.selectSingleNode("servlet-name");
            Element urlEl = (Element) el.selectSingleNode("url-parttern");
            String servletName = servletNameEl.getStringValue();
            String url = urlEl.getStringValue();
            servletMappingInfo.put(servletName,url);
        }
        Set<String> keySet = servletMapInfo.keySet();
        Map<String,String> servletMap = new HashMap<>();
        for (String servletName:keySet) {
            String servletClass = servletMapInfo.get(servletName);
            String urlParttern = servletMappingInfo.get(servletName);
            servletMap.put(urlParttern,servletClass);
        }
        return servletMap;
    }
}

1.7 创建带响应和请求参数的接口

public interface Servlet {

    public void service(ServletResponse response,ServletRequest request);
}

1.8 创建缓冲池

将解析到的地址和类路径储存到缓冲池中,使用时再在缓冲池中取值。

public class ServletCache {
    private static Map<String, Servlet> map = new HashMap<>();
    //存servlet
    public static void put(String name,Servlet servlet){
        map.put(name,servlet);
    }
    //取servlet
    public  static Servlet get(String name){
        return map.get(name);
    }
}

1.9 创建服务器响应接口和实现该接口的类

//接口
public interface ServletResponse {

    public void setWrite(PrintWriter write);

    public PrintWriter getWrite();
}

//实现类
public class ResponseObj implements ServletResponse {

    private  PrintWriter out;
    @Override
    public void setWrite(PrintWriter out) {
        this.out = out;
    }

    @Override
    public PrintWriter getWrite() {
        return out;
    }
}

1.10 创建处理请求的接口

接口中提供获取单个参数的方法和获取列表多个参数的方法。

public interface ServletRequest {
    String getParameterValue(String key);
    String[] getParameterValues(String key);
}

1.11 创建处理用户输入表单的信息

获取用户输入表单的提交的信息,通过处理请求,将信息处理,并将信息输出到网页上

public class SaveUserServlet implements Servlet {
    @Override
    public void service(ServletResponse response, ServletRequest request) {
        //处理表单的servlet
        String username = request.getParameterValue("username");
        String gender = request.getParameterValue("gender");
        String[] interests = request.getParameterValues("interest");
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.1 200 ok\n");
        sb.append("content-type:text/html;charset=utf-8\n\n");
        sb.append("<html>");
        sb.append("<head><meta charset='utf-8'></head>");
        sb.append("<body>");
        sb.append("用户名:" + username + "<br/>");
        sb.append("性别:" + gender + "<br/>");
        sb.append("爱好");
        for (String interest:interests) {
            sb.append(interest).append(" ");
        }
        sb.append("<br/>");
        sb.append("</body>");
        sb.append("</html>");
        response.getWrite().print(sb);
        
    }

1.12 创建处理需求类,实现需求接口

类中重写实现接口的方法,分别为获取单个参数的方法和获取列表的多个参数的方法,创建根据用户输入信息后提交的路径地址,获取用户输入的信息,将信息以键值对的方式存入map集合中的构造函数。

    public RequestObj(String path){
        if(path.contains("?")){
            //参数部分
            String dataAndParam = path.split("[?]")[1];
            if(dataAndParam.length() > 1){
                //多个参数
                if(dataAndParam.contains("&")){
                    String[] nameAndValues = dataAndParam.split("[&]");
                    for (String nameAndValue:nameAndValues) {
                        String[] param = nameAndValue.split("[=]");
                        if(paramMap.containsKey(param[0])){
                            //多选框
                            //获取原来的值
                            String[] old_value = paramMap.get(param[0]);
                            //当前的值 定义一个新的数组,新的数组的长度比原来的数组长度+1
                            String[] newValues = new String[old_value.length+1];
                            //将原来的数组的值传给新数组
                            System.arraycopy(old_value,0,newValues,0,old_value.length);
                            //判断当前参数
                            if(param.length > 1) {
                                newValues[newValues.length-1] = param[1];
                            }else {
                                newValues[newValues.length-1] = "";
                            }
                            paramMap.put(param[0],newValues);
                        }else{
                            //普通输入框
                            if(param.length > 1){
                                paramMap.put(param[0],new String[]{param[1]});
                            }else{
                                paramMap.put(param[0],new String[]{""});
                            }
                        }
                    }
                }else{
                    //单个参数
                    String[] param = dataAndParam.split("[=]");
                    if(param.length > 1){
                        paramMap.put(param[0],new String[]{param[1]});
                    }
                }
            }
        }
    }

    @Override
    public String getParameterValue(String key) {
        String[] values = paramMap.get(key);
        return (values != null && values.length != 0) ? values[0] : null;
    }

    @Override
    public String[] getParameterValues(String key) {
        return paramMap.get(key);
    }

2.Tomcat的使用

2.1 创建实现Servlet接口的实现类

(1)新建一个空项目,并选择web服务器和选择Web Application ;

(2)创建完成后,创建项目模块,鼠标左键点击项目模块,在上侧栏选择Edit Configurations配置tomcat服务器;

(3)修改xml文件

(4)创建实现Servlet接口的实现类,并在类中重写实现接口的方法

public class HelloServlet implements Servlet {

    public HelloServlet(){
        System.out.println("构造函数.....");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init......");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("helloServlet.......");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String method = request.getMethod();
        if("GET".equals(method)){
            System.out.println("GET处理");
        }else {
            System.out.println("POST处理");
        }
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

2.2 创建继承HttpServlet父类的子类

(1)新建一个空项目,并选择web服务器和选择Web Application ;

(2)创建完成后,创建项目模块,鼠标左键点击项目模块,在上侧栏选择Edit Configurations配置tomcat服务器;

(3)修改xml文件

(4)创建继承HttpServlet父类的子类,在子类中重写父类的doGet()方法和doPost()方法

public class RequestServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //getRequestURI() 获取请求的资源路径
        System.out.println("uri:" + req.getRequestURI());
        //getRequestURL() 获取请求的统一资源定位符(绝对路径)
        System.out.println("url:" + req.getRequestURL());
        //getRemoteHost() 获取客户端的 ip 地址
        System.out.println("ip:" + req.getRemoteHost());
        //getHeader() 获取请求头
        System.out.println("header:" + req.getHeader("User-Agent"));
        //getMethod() 获取请求的方式 GET 或 POST
        System.out.println("method:" + req.getMethod());
        //getParameter() 获取请求的参数
        System.out.println(req.getParameter("username"));
        System.out.println(req.getParameter("password"));
        //getParameterValues() 获取请求的参数(多个值的时候使用)
        System.out.println(Arrays.toString(req.getParameterValues("hobby")));
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }
}

2.3 直接在空项目模块中创建Servlet

(1)新建一个空项目,并选择web服务器和选择Web Application ;

(2)创建完成后,创建项目模块,鼠标右击项目模块,快捷创建Servlet;

(3)创建完成后,修改xml文件,接着,创建继承HttpServlet父类的子类,在子类中重写父类的doGet()方法和doPost()方法

public class ServletContext3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        Integer count = (Integer) servletContext.getAttribute("count");
        if(count == null){
            count = 1;
        }else {
            count++;
        }
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().print("<h1>本页面一共被访问" + count + "次</h1>");
        servletContext.setAttribute("count",count);
    }
}

3.总结

      自定义tomcat服务器,让我们能更好地理解tomcat各种api的作用和使用方式以及原理,让我们能更直观的了解和掌握tomcat,能让我们能更高效地使用tomcat去完成项目。tomcat的使用的三种方式,实现Servlet接口的方式比较麻烦,但能让我们了解Serlet接口内的api;继承HttpServlet的方法能减少不使用但要重写的方法,减少代码冗余;直接创建Servlet的方式,能更便捷的使用tomcat,只需要添加xml中对应的servletMapping。

4.建议采纳

如有建议或者错误请私信我进行修改,感谢!!!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值