Tomcat有三种运行模式(BIO,NIO,APR),这里我们来模拟BIO线程模型模拟Tomcat。
Tomcat的运行流程:
当用户在浏览器地址栏输入url,一回车就会发出一个HTTP请求。
这个请求到达Tomcat过后,由tomcat里的Socket网络编程接收请求,它接收这个请求之后就会创建一个线程,一个请求对应一个线程。启动线程去处理请求,这个线程就会分析,解析请求URL,如果发现请求是Servlet就会调用对应的Servlet完成业务,如果是静态资源就会直接返回。
首先我们知道Tomcat的运行机制是这样,分为三个阶段
基于Socket开发服务流程(第一阶段)
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Author: 诉衷情の麻雀
* @Description: 第一个版本的tomcat, 可以完成接收浏览器的请求,并返回信息
* @DateTime: 2023/7/3 11:59
**/
public class tomcat {
public static void main(String[] args) throws IOException {
//1.创建ServerSocket, 在8080端口监听
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("=====mytomcat在8080端口监听=====");
while (!serverSocket.isClosed()) {
//等待浏览器/客户端的连接
//如果有连接就创建一个socket
Socket socket = serverSocket.accept();
//先接收浏览器发送的数据
// 字节流 => BufferedReader(字符流)
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String mes = null;
System.out.println("=====接收到浏览器发送的数据==========");
//循环的读取
while ((mes = bufferedReader.readLine()) != null) {
//判定mes的长度是否为0
if (mes.length() == 0) {
break; //退出循环
}
System.out.println(mes);
}
//我们的tomcat回送http响应方式
OutputStream outputStream = socket.getOutputStream();
//构建一个http响应体
String respHeader = "HTTP/1.1 200\r\n" +
"Content-Type: text/html;charset=utf-8\r\n\r\n";
String resp = respHeader + "hi,诉衷情的麻雀";
System.out.println("***********自定义的tomcat返回的数据如下:****************");
System.out.println(resp);
outputStream.write(resp.getBytes()); //将resp字符串以byte[]方式返回
outputStream.flush();
outputStream.close();
inputStream.close();
socket.close();
}
}
}
控制台信息:
C:\Users\27837\.jdks\corretto-1.8.0_372\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.2\lib\idea_rt.jar=49337:C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.2\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\charsets.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\access-bridge-64.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\cldrdata.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\dnsns.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\jaccess.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\jfxrt.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\localedata.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\nashorn.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\sunec.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\sunjce_provider.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\sunmscapi.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\sunpkcs11.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\ext\zipfs.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\jce.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\jfr.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\jfxswt.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\jsse.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\management-agent.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\resources.jar;C:\Users\27837\.jdks\corretto-1.8.0_372\jre\lib\rt.jar;C:\Users\27837\IdeaProjects\SparrowTomcat2\target\classes tomcat
=====mytomcat在8080端口监听=====
=====接收到浏览器发送的数据==========
GET /calServlet?num1=9&num2=8 HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Microsoft Edge";v="114"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.67
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8080/cal.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: adminUserName=admin; Hm_lvt_cd8218cd51f800ed2b73e5751cb3f4f9=1685415115,1685417440,1685417753,1686711339; studentUserName=student; remember-me=c3R1ZGVudDoxNjg5MzAzNjE5MTcwOjVhY2I0ZmIwOWNkNzlhOGNhMzk2Y2VjMzYxN2U3YTA2; Idea-cbb45668=ad78c5a9-9163-44be-bea9-5e6e627f4d28; Pycharm-5a41dc58=6b00e104-f55a-4310-8cad-877cb8a7b5bf; Webstorm-d0f6cdaf=9c2a0698-aac2-42f2-924c-3bf948a95d65; JSESSIONID=8ED27513A220BF1F4CF218CB3E886E61
***********自定义的tomcat返回的数据如下:****************
HTTP/1.1 200
Content-Type: text/html;charset=utf-8
hi,诉衷情的麻雀
=====接收到浏览器发送的数据==========
***********自定义的tomcat返回的数据如下:****************
HTTP/1.1 200
Content-Type: text/html;charset=utf-8
hi,诉衷情的麻雀
因为这个阶段只是单线程,现在我们来模拟多线程
使用BIO线程模型,支持多线程(版本2)
package com.sparrow.servlet.tomcat.handler;
import java.io.*;
import java.net.Socket;
/**
* @Author: 诉衷情の麻雀
* @Description: 是一个线程对象
* 处理一个http请求的
* @DateTime: 2023/7/3 12:57
**/
public class RequestHandler implements Runnable {
//定义Socket
private Socket socket = null;
public RequestHandler(Socket socket) {
this.socket = socket;
}
public void run() {
//这里我们可以对客户端/浏览器进行IO编程/交互
try {
InputStream inputStream = socket.getInputStream();
//把InputStream -> BufferedReader 方便进行按行读取
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
System.out.println("当前的线程:" + Thread.currentThread().getName());
System.out.println("*******tomcatV2接收到的数据如下***********");
String mes = null;
while ((mes = bufferedReader.readLine()) != null) {
//如果长度为0 是空字符串”“
if (mes.length() == 0) {
break;
}
System.out.println(mes);
//构建http响应头
//返回http的响应头之间有两个换行
String respHeader = "HTTP/1.1 200\r\n" +
"Content-Type: text/html;charset=utf-8\r\n\r\n"; //根据HTTP响应头规则 这里要换一行
String resp = respHeader + "<h1>Hi 诉衷情の麻雀</h1>";
System.out.println("********TomcatVe返回的数据如下:***************");
//返回数据给我们的浏览器/客户端->封装成http响应
OutputStream outputStream = socket.getOutputStream();
outputStream.write(resp.getBytes());//将resp字符串以byte[]方式返回
outputStream.flush();
outputStream.close();
inputStream.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
package com.sparrow.servlet;
import com.sparrow.servlet.tomcat.handler.RequestHandler;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Author: 诉衷情の麻雀
* @Description: TODO
* @DateTime: 2023/7/3 13:12
**/
public class tomcatV2 {
public static void main(String[] args) throws IOException {
//在8080端口监听
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("==========tomcatV2在8080端口监听================");
//只要serverSocket没有关闭,就一直等待浏览器/客户端连接
while (!serverSocket.isClosed()) {
//1.接收到浏览器的连接后,如果成功,就会得到socket
//2.这个socket就是服务器和浏览器的数据通道
Socket socket = serverSocket.accept();
//3.创建一个线程对象,并且把socket给该线程
new Thread(new RequestHandler(socket)).start();
}
}
}
自己封装HttpRequest对象
package com.sparrow.servlet.http;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
/**
* @Author: 诉衷情の麻雀
* @Description: 封装http请求的数据
* 比如 method get/post URi/参数
* @DateTime: 2023/7/3 13:55
**/
public class SparrowRequest {
private String method;
private String uri;
//存放参数列表 参数名->参数值 HashMap
private HashMap<String, String> parameterMapping = new HashMap<String, String>();
private InputStream inputStream = null;
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public SparrowRequest(InputStream inputStream) {
this.inputStream = inputStream;
//完成对http请求数据的封装...
init();
}
//request对象有个特别重要的方法
public String getParameter(String name) {
if (parameterMapping.containsKey(name)) {
return parameterMapping.get(name);
}else {
return "";
}
}
//构造器=> http请求封装 然后提供相关的方法获取
//inputStream是和对应http请求的socket关联
public void init() {
System.out.println("init被调用了........");
//inputStream->BufferedReader
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
//读取第一行
/**
* GET /calServlet?num1=9&num2=8 HTTP/1.1
*/
String requestLine = bufferedReader.readLine();
String[] requestLineArr = requestLine.split(" ");
method = requestLineArr[0];
//解析得到 /calServlet
//1.先看看uri有没有参数列表
int index = requestLineArr[1].indexOf("?");
if (index == -1) { //说明没有参数列表
uri = requestLineArr[1];
}else {
//[0,index)
uri = requestLineArr[1].substring(0, index);
//获取参数列表->parametersMapping
//parameters num1=9&num2=8
String parameters = requestLineArr[1].substring(index + 1);
String[] parametersPair = parameters.split("&");
//防止用户提交/calServlet?
if (null != parametersPair && !"".equals(parametersPair)) {
//再次分割
for (String parameterPair : parametersPair) {
//parameterVal ["num1","9"] ["num2","8"]
String[] parameterVal = parameterPair.split("=");
if (parameterVal.length == 2) {
//放入到parametersMapping
parameterMapping.put(parameterVal[0], parameterVal[1]);
}
}
}
}
//这里不能关闭inputStream
// inputStream.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return "SparrowRequest{" +
"method='" + method + '\'' +
", uri='" + uri + '\'' +
", parameterMapping=" + parameterMapping +
'}';
}
}
封装HttpResponse对象
package com.sparrow.servlet.http;
import java.io.OutputStream;
/**
* @Author: 诉衷情の麻雀
* @Description: Response对象可以封装OutputStream(是socket关联)
* Response对象的作用等价于原生的servlet的HttpServletResponse
* @DateTime: 2023/7/3 13:58
**/
public class SparrowResponse {
private OutputStream outputStream = null;
//http的响应头
public static final String respHeader ="HTTP/1.1 200\r\n" +
"Content-Type: text/html;charset=utf-8\r\n\r\n";
//OutputStream是和对应http请求的socket关联
public SparrowResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
//当我们需要给浏览器返回数据时,可以通过SparrowResponse的输出流完成
public OutputStream getOutputStream() {
return outputStream;
}
}
改进线程对象Handler
package com.sparrow.servlet.tomcat.handler;
import com.sparrow.servlet.SparrowCalServlet;
import com.sparrow.servlet.http.SparrowRequest;
import com.sparrow.servlet.http.SparrowResponse;
import java.io.*;
import java.net.Socket;
/**
* @Author: 诉衷情の麻雀
* @Description: 是一个线程对象
* 处理一个http请求的
* @DateTime: 2023/7/3 12:57
**/
public class RequestHandler implements Runnable {
//定义Socket
private Socket socket = null;
public RequestHandler(Socket socket) {
this.socket = socket;
}
public void run() {
//这里我们可以对客户端/浏览器进行IO编程/交互
try {
InputStream inputStream = socket.getInputStream();
SparrowRequest sparrowRequest = new SparrowRequest(inputStream);
SparrowResponse sparrowResponse = new SparrowResponse(socket.getOutputStream());
//创建SparrowCalServlet对象
SparrowCalServlet sparrowCalServlet = new SparrowCalServlet();
sparrowCalServlet.doGet(sparrowRequest, sparrowResponse);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
构建HttpServlet
package com.sparrow.servlet;
import com.sparrow.servlet.http.SparrowRequest;
import com.sparrow.servlet.http.SparrowResponse;
import java.io.IOException;
/**
* @Author: 诉衷情の麻雀
* @Description: TODO
* @DateTime: 2023/7/3 13:51
**/
public abstract class SparrowHttpServlet implements SparrowServlet{
public void service(SparrowRequest request, SparrowResponse response) throws IOException {
if ("GET".equalsIgnoreCase(request.getMethod())) {
this.doGet(request, response);
} else if ("POST".equalsIgnoreCase(request.getMethod())) {
this.doPost(request, response);
}
}
//使用模板设计模式 延迟到子类Servlet实现
public abstract void doGet(SparrowRequest request, SparrowResponse response);
public abstract void doPost(SparrowRequest request, SparrowResponse response);
}
自定义Servlet
package com.sparrow.servlet;
import com.sparrow.servlet.http.SparrowRequest;
import com.sparrow.servlet.http.SparrowResponse;
import com.sparrow.servlet.utils.WebUtils;
import java.io.IOException;
import java.io.OutputStream;
/**
* @Author: 诉衷情の麻雀
* @Description: TODO
* @DateTime: 2023/7/3 13:53
**/
public class SparrowCalServlet extends SparrowHttpServlet{
public void doGet(SparrowRequest request, SparrowResponse response) {
System.out.println("SparrowCalServlet被调用了...");
//写业务代码完成计算任务
int num1 = WebUtils.parseInt(request.getParameter("num1"), 0);
int num2 = WebUtils.parseInt(request.getParameter("num2"), 0);
int sum = num1 + num2;
//返回结果数据
OutputStream outputStream = response.getOutputStream();
String respMes = SparrowResponse.respHeader + "<h1>" + num1 + " + " + num2 + " = " + sum + "</h1>";
try {
outputStream.write(respMes.getBytes());
outputStream.flush();
outputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void doPost(SparrowRequest request, SparrowResponse response) {
this.doGet(request, response);
}
public void init() throws Exception {
}
public void destroy() {
}
}
处理Servlet(版本3)
这是原生的HttpServlet类的结构图
现在我们自己定义一个Servlet接口规范和HttpServlet抽象类,然后写一个CalServlet继承自定义的Servlet
构建一个容器
package com.sparrow.servlet;
import com.sparrow.servlet.tomcat.handler.RequestHandler;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author: 诉衷情の麻雀
* @Description: 实现通过xml+反射来初始化容器
* @DateTime: 2023/7/3 16:34
**/
public class tomcatV3 {
//1.存放容器servletMapping
//HashMap
//key -value
//ServletName 对应的实例
public static final ConcurrentHashMap<String, SparrowHttpServlet> servletMapping = new ConcurrentHashMap<String, SparrowHttpServlet>();
//2.还有一个容器servletURLMapping
//ConcurrentHashMap
//HashMap key - value
//url-Pattern ServletName
public static final ConcurrentHashMap<String, String> servletUrlMapping = new ConcurrentHashMap<String, String>();
//tomcat还维护一个容器 存放session
public static final ConcurrentHashMap<String, HttpSession> sessionMapping = new ConcurrentHashMap<String, HttpSession>();
//tomcat还维护了filter的容器
public static final ConcurrentHashMap<String, String> filterUrlMapping = new ConcurrentHashMap<String, String>();
public static final ConcurrentHashMap<String, Filter> filterMapping = new ConcurrentHashMap<String, Filter>();
//直接对两个容器进行初始化
public void init() {
//读取web.xml => dom4j
//得到web.xml文件的路径
String path = tomcatV3.class.getResource("/").getPath();
System.out.println("path=" + path);
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(new File(path + "web.xml"));
System.out.println(document);
//得到根元素
Element rootElement = document.getRootElement();
//得到根元素下面所有的元素
List<Element> elements = rootElement.elements();
//遍历并过滤Servlet servletMapping
for (Element element : elements) {
if("servlet".equalsIgnoreCase(element.getName())){
//这是一个Servlet配置
//使用反射将该servlet实例放入到servletMapping
Element servletName = element.element("servlet-name");
Element servletClass = element.element("servlet-class");
servletMapping.put(servletName.getText().trim(),(SparrowHttpServlet) Class.forName(servletClass.getText().trim()).newInstance());
} else if ("servlet-mapping".equalsIgnoreCase(element.getName())) {
//这是一个servlet-mapping配置
System.out.println("发现了servlet-mapping的配置");
Element servletName = element.element("servlet-name");
Element urlPattern = element.element("url-pattern");
servletUrlMapping.put(urlPattern.getText(),servletName.getText());
}
}
} catch (DocumentException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
//验证这两个容器是否初始化
System.out.println("servletMapping=" + servletMapping);
System.out.println("servletUrlMapping=" + servletUrlMapping);
}
public static void main(String[] args) {
tomcatV3 tomcatV3 = new tomcatV3();
tomcatV3.init();
//启动tomcat容器
tomcatV3.run();
}
//启动tomcatV3容器
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("********tomcatV3在8080端口监听**********8");
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
RequestHandler requestHandler = new RequestHandler(socket);
new Thread(requestHandler).start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
修改RequestHandler
package com.sparrow.servlet.tomcat.handler;
import com.sparrow.servlet.SparrowCalServlet;
import com.sparrow.servlet.SparrowHttpServlet;
import com.sparrow.servlet.http.SparrowRequest;
import com.sparrow.servlet.http.SparrowResponse;
import com.sparrow.servlet.tomcatV3;
import java.io.*;
import java.net.Socket;
/**
* @Author: 诉衷情の麻雀
* @Description: 是一个线程对象
* 处理一个http请求的
* @DateTime: 2023/7/3 12:57
**/
public class RequestHandler implements Runnable {
//定义Socket
private Socket socket = null;
public RequestHandler(Socket socket) {
this.socket = socket;
}
public void run() {
//这里我们可以对客户端/浏览器进行IO编程/交互
try {
SparrowRequest sparrowRequest = new SparrowRequest(socket.getInputStream());
SparrowResponse sparrowResponse = new SparrowResponse(socket.getOutputStream());
//创建SparrowCalServlet对象
//1.得到uri->servletName->servlet的实例,真正的运行类型是其子类sparrowCalServlet
String uri = sparrowRequest.getUri();
String servletName = tomcatV3.servletUrlMapping.get(uri);
if (servletName == null) {
servletName = "";
}
//2.通过uri->servletName->servlet的实例
SparrowHttpServlet sparrowHttpServlet = tomcatV3.servletMapping.get(servletName);
//3.调用service方法,通过oop的动态绑定机制,调用运行类型的doGet/doPost
if (sparrowHttpServlet != null) {
sparrowHttpServlet.service(sparrowRequest,sparrowResponse);
}else {
//没有这个servlet返回404
String resp = SparrowResponse.respHeader + "<h1>404 Not Found</h1>";
OutputStream outputStream = sparrowResponse.getOutputStream();
outputStream.write(resp.getBytes());
outputStream.flush();
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
web.xml
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>SparrowCalServlet</servlet-name>
<servlet-class>com.sparrow.servlet.SparrowCalServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SparrowCalServlet</servlet-name>
<url-pattern>/sparrowCalServlet</url-pattern>
</servlet-mapping>
</web-app>
//1.得到uri->servletName->servlet的实例,真正的运行类型是其子类sparrowCalServlet
String uri = sparrowRequest.getUri();
if(WebUtils.isHtml(uri)){ //就是静态页面
String content = WebUtils.readHtml(uri.substring(1));
content = SparrowResponse.respHeader + content;
System.out.println("content=" + content);
//准备返回 得到outputStream,返回信息给浏览器
OutputStream outputStream = sparrowResponse.getOutputStream();
outputStream.write(content.getBytes());
outputStream.flush();
outputStream.close();
socket.close();
return;
}
在这里再增加是否是静态资源 如果是html则返回
WebUtils
package com.sparrow.servlet.utils;
import com.sparrow.servlet.tomcatV3;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
/**
* @author 诉衷情の麻雀
* @Description TODO
* @date 2023/7/2
* @Version 1.0
*/
public class WebUtils {
/**
* 将一个字符串数字转为int,如果转换失败 返回默认值
* @param strNum
* @param defaultVal
* @return
*/
public static int parseInt(String strNum, int defaultVal) {
try {
return Integer.parseInt(strNum);
} catch (NumberFormatException e) {
System.out.println(strNum + " 格式不对 转换失败");
}
return defaultVal;
}
//判定uri是不是html文件
public static boolean isHtml(String uri) {
return uri.endsWith(".html");
}
//根据文件名来读取该文件->String
public static String readHtml(String filename) {
String path = tomcatV3.class.getResource("/").getPath();
StringBuilder stringBuilder = new StringBuilder();
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(path + filename));
String buf = "";
while ((buf = bufferedReader.readLine()) != null) {
stringBuilder.append(buf);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return stringBuilder.toString();
}
}