java servlet,mvc
servlet是一个java接口,用于处理http请求,生成响应
Servlet 的意义 —— 把“请求处理”做成可管理、可复用的 Java 对象,对一个路径的请求对应一个servlet类
它在 javax.servlet 包里定义,大概长这样:
public interface Servlet {
void init(ServletConfig config) throws ServletException;
void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
void destroy();
ServletConfig getServletConfig();
String getServletInfo();
}
service() 是 Servlet 接口里最核心的方法。它的作用是:每次收到一个请求时执行,用来处理请求和返回响应。,Tomcat自动会调用它
doGet() 和 doPost()是在httpservlet里用来处理两种http请求的方法
servlet里:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
resp.getWriter().write("这是GET请求");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
resp.getWriter().write("这是POST请求");
}
在最早期(没有 Spring 这些框架的时候),开发 Web 应用时,一个 Servlet 既充当了控制器(接收请求),又写了业务逻辑
rep(请求),resp(响应)
httpservletRequest(req)
由浏览器发起的 HTTP 请求报文(包括 URL、参数、请求头、cookie、body 等)
Tomcat 收到浏览器的 HTTP 报文后,会把这些信息解析好,封装成一个 Java 对象 HttpServletRequest,然后交给 Servlet 用。
常用方法:
getparameter("name") 取参数的值
getheader("user-agent") 取请求头,比如浏览器类型ua头
setattribute("user",obj) 往request里存对象
getattribute("user") 取服务器端放的数据
httpservletresponse (resp)
代表“响应对象”,用来构造发回浏览器的 HTTP 响应报文
常用方法:
setcontenttype("text/html;charset=utf-8" ) 告诉浏览器编码类型
getwriter() 获取一个写出工具
getoutputstream() 获取字节流工具(适合图片,文件下载)
getwriter().write("hello") 把字符串写进响应体
tomcat
servlet必须运行在tomcat这种java web容器上,可以把servlet想象成服务员,tomcat就是老板,老板提供服务员工作的地方(餐厅),也指导服务员的工作
它与普通服务器(如apache)的区别在于,apache的主要职责是返回静态资源,但也可以通过扩展模块(mod_php)运行动态语言,我们电脑上下载的apache服务器能跑php就是因为默认已经下好了mod_php,但本质上它更擅长静态文件的转发 ,实际环境中,经常是使用apache把动态请求转发给tomcat处理
在webapps/下上传war包
webapps/
├── ROOT.war (公司官网)
├── shop.war (电商系统)
├── admin.war (管理系统)
└── blog.war (博客系统)
tomcat会自动解压为:
webapps/
├── ROOT/ ← http://yoursite.com/
├── shop/ ← http://yoursite.com/shop/
├── admin/ ← http://yoursite.com/admin/
└── blog/ ← http://yoursite.com/blog/
war
war包就是把 Java Web 应用及其运行所需内容打包成一个文件(包括静态文件,动态文件),便于部署到容器(如 Tomcat)。
jsp
JSP 是一种文件格式(html+java),jsp文件的后缀是.jsp,基于java生态系统
一个 .jsp 文件通常包含三种内容:
- 静态内容 → HTML、CSS、JS,这些会原封不动输出到浏览器。
- Java 表达式,语句,具体来说,有以下三种:
<% ... %>里放 Java 语句,即一个java片段,里面的内容会被tomcat直接翻译成servlet里的java语句<%= ... %>里放 Java 表达式,该表达式执行后的结果直接输出到页面<%! ... %>里放类的声明。 翻译时会放到 Servlet 类的成员变量里。<%@ %>导入包、设置页面属性
- JSP 标签 → 例如
<jsp:include .../>,他们是标准化的功能块,比脚本更稳定 - EL 表达式
${user.name},它是一门小语言,专门给 JSP 用的,可以写到sturts标签内,可以看做ognl的简化版,可以访问作用域对象里的数据(request, session, application),访问请求参数(param, header, cookie 等),做简单的运算、逻辑判断(${a + b},${a > b ? 'yes' : 'no'})等
常用EL表达式:
${user.name} - 获取user对象的name属性
${param.username} - 获取请求参数username的值
${sessionScope.user} - 获取session中的user对象
${list[0]} - 获取list集合的第一个元素
tomcat在处理 JSP 时,不是直接原样输出,而是把它们转换成servlet类,再执行。
比如写一个hello.jsp:
<html>
<body>
Hello, <%= request.getParameter("name") %>!
</body>
</html>
Tomcat 等容器会把它翻译成一个 Servlet,大概长这样 , hello_jsp.java
//定义一个hello_jsp类
public class hello_jsp extends HttpServlet {
public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 获取输出流
JspWriter out = response.getWriter();
// 把 HTML 输出成字符串
out.write("<html>\n<body>\nHello, ");
out.write(request.getParameter("name")); // <%= ... %> 被翻译成 Java 输出
out.write("!\n</body>\n</html>");
}
}
HTML 部分 → 被翻译成 out.write("...")。
JSP 表达式 <%= ... %> → 被翻译成 Java 代码并执行,结果写进输出流
所以我们才说,jsp中的:
HTML 是静态部分,直接输出。
JSP 标签/表达式是动态部分,要转成 Java 代码后运行。
浏览器请求http://localhost:8080/hello.jsp?name=Tom时, Tomcat 运行 hello_jsp._jspService(),拼接出完整的 HTML, JSP 本质就是生成 HTML 的模板。
<html>
<body>
Hello, Tom!
</body>
</html>
_jspService() 是一个servlet类的方法,在普通的 Servlet 里,处理请求的方法是 doGet() 或 doPost()。但 JSP 是一种“特殊的 Servlet”,它没有自己写的 doGet/doPost,Tomcat 会帮你生成一个固定的方法:public void _jspService(HttpServletRequest req, HttpServletResponse resp),这个 _jspService 方法就是 JSP 页面的核心逻辑,用来生成 HTML。每次浏览器请求这个 JSP 时,Tomcat 就调用这个方法。
- 普通 Servlet:容器调用
service()→ 里面再分发到doGet/doPost。 - JSP Servlet:容器调用
service()→ 里面直接执行_jspService()。
mvc模式
MVC模式是人们为了解决Web应用开发混乱问题而设计出的架构模式 ,把一个web应用分成三部分: Model(bean),负责处理业务逻辑,View(jsp)负责从model中获取数据并生成用户看到的html页面,Controller(servlet)负责接收请求,并调用对应的model
java里实现mvc模式用的往往都是spring生态,因为生态成熟,整合方便,spring生态中,对于web层,使用spring mvc框架实现,对于业务层,主要是写业务逻辑,这里不需要一个专门的“业务框架”,而是需要一个能管理对象、解耦调用的容器。这就是 Spring 核心容器(ApplicationContext) 发挥作用的地方,你写一个 @Service 类,Spring 自动帮你实例化、管理生命周期。你写一个 @Autowired,Spring 自动帮你把需要的依赖对象注入进来。所以 业务层的框架就是 Spring 自身(IoC + AOP)。对于持久层,负责数据库操作,常见框架:Hibernate(ORM),在 Spring 生态里,有 Spring Data 来统一整合持久层框架:
Spring Data JPA → 封装 Hibernate
Spring Data MongoDB → 操作 MongoDB
Spring Data Redis → 操作 Redis
所以持久层既有 Hibernate/MyBatis 这些“外部框架”,也有 Spring 提供的统一封装(Spring Data)。
Spring 生态不是单独在哪一层,而是贯穿三层,
- Spring MVC 管 Web 层
- Spring IoC/AOP 管业务层
- Spring Data 管持久层
- 再加上 Spring Boot 把它们打包成一个完整的项目启动器
→ 这就是 Spring 生态。
Spring Framework
├── spring-core (核心功能)
├── spring-web (Web基础)
├── spring-webmvc (MVC框架) ← 你熟悉的
├── spring-webflux (响应式Web)
├── spring-data (数据访问)
└── ...其他模块
1. 表示层(web层):
Struts2 和 Spring MVC 都是表示层的框架。Struts2 是独立的 Web 框架,不依赖 Spring(但可以整合)。Spring MVC 是 Spring 家族的一部分,本身和 Spring Core 天然契合,所以后来大家更多用 Spring MVC 替代 Struts2,web层不会做一些复杂的逻辑,即设计业务逻辑的部分,他只是取出浏览器传来的数据,再交给业务层实现业务逻辑
有三个重要概念;
前端控制器,他是框架的总入口,在struts2里叫FilterDispatcher,spring mvc里叫DispatcherServlet, DispatcherServlet是一个servlet的实现类(经过了层层继承) ,最初我们要写很多的servlet,接受不同的请求在选择调用get方法还是post方法,但是现在在 Spring MVC 中,只有一个servlet,即dispatcherservlet,所有请求先到 DispatcherServlet,它只负责找到对应的Controller类,执行Controller类,而controller类会调用业务层,再把结果交给 View 解析器,去渲染页面
拦截器,在spring mvc和struts2里都叫intercepter,它运行在控制器前后,常见用途有登录校验(未登录就跳转到登录页),权限检查,记录日志,性能监控(统计接口耗时)等
控制器controller,他是MVC里的C, 负责接收用户请求,然后决定交给哪个 Service 来处理。实际上是一个类,不同url对应不同的controller,也就执行不同的逻辑功能
在不同框架里的表现:
Servlet 时代:你自己写 LoginServlet,就是控制器。
Struts2:框架要求你写一个 Action 类,比如 LoginAction,Struts2 框架会帮你把请求转发到这个 Action 类里。
Spring MVC:着重讲下,
spring mvc里的controller类是靠 @Controller 注解的,它就标明了,这不是一个普通的类,而是一个controller类,这样DispatcherServlet就可以找到了
@Controller
public class UserController {
@GetMapping("/hello")
public String hello() {
return "hello.jsp";
}
}
但是光有控制器还不够,还得告诉 Spring:请求进来时,要走哪个方法。
这就是 @RequestMapping、@GetMapping、@PostMapping 的作用,他们都是用来标记方法的,当然这些方法都是引进的service的
@RequestMapping —— 通用映射
最早的版本里,Spring 只有这个注解。它可以:
标在类上:给整个类的请求路径加个“前缀”。
标在方法上:给具体方法绑定请求路径。
默认可以处理 GET、POST、PUT、DELETE… 任何请求。
@Controller
@RequestMapping("/user") // 类级别前缀
public class UserController {
@RequestMapping("/list") // 方法级别路径
public String listUsers() {
return "userList"; // 访问 /user/list 时,这个方法会被调用,返回视图名
}
}
@GetMapping —— 标记专门处理 GET 请求的方法
@GetMapping("/list")
public String listUsers() {
return "userList";
}
@PostMapping —— 标记专门处理 POST 请求的方法
@PostMapping("/save")
public String saveUser(User user) {
return "success";
}
Spring 容器启动时,容器会找到所有 @Controller 的类(包括所有被标记的类)
自动实例化这些类(new 出对象),并存到 IoC 容器里,Spring 会把这些对象注册成Bean,类似于 Map<String, Object> 这样的存储结构。Bean 的 key 可以是类名(比如 "userController"),value 就是那个对象。DispatcherServlet 调用时,直接从容器里取对象,请求到达 DispatcherServlet,它会解析 URL → 找到对应的 Controller 对象 → 用反射调用其中的方法。
所以,在 Spring 里,不需要写 new UserController(),spring 启动时就帮你 new 好了。
Bean
Bean是一个广泛的概念,只要是被 Spring 容器管理的对象都叫Bean,我们写的普通类,只要交给了 Spring 容器(通过注解 @Component / @Service / @Controller / @Repository,或者 XML 配置),Spring 就会创建它的对象并托管生命周期。
mvc中的其他注解
@Service 注解
用来标记业务层的类。
加了这个注解以后,Spring 会把这个类交给容器管理,生成一个 Bean。
@Service
public class UserService {
public void addUser() {
System.out.println("User added.");
}
}
@Repository注解
用来标记数据访问层(DAO层)的类,告诉spring,这个类是负责访问数据的
@Autowired 注解
用来自动注入依赖。
当一个类需要另一个 Bean 时,Spring 会自动帮你把那个 Bean 放进来。
@Controller
public class UserController {
@Autowired // 自动把 UserService 注入进来
private UserService userService;
public String add() {
userService.addUser(); // 不需要手动 new
return "success";
}
}
@RestController注解
用于前后端分离,或者 AJAX / Fetch 请求
@Controller返回的是 视图(页面),比如 return "login.jsp";,最后由前端(JSP/Thymeleaf)去渲染页面。而@RestController返回的是数据(JSON / XML),不会去找页面
@RestController = @Controller + @ResponseBody
容器(ApplicationContext)
在 Spring 里,容器就是一个大工厂
它的工作是:
扫描项目中的类(带注解的,比如 @Controller、@Service、@Repository…)。
创建对象(实例化),并管理这些对象。
维护依赖关系,谁需要谁,就自动“注入”进去。
所以,当你启动一个 Spring 应用时,第一件事就是容器启动,它会把所有需要的 Bean 都准备好。
IoC(Inversion of Control,控制反转)
IoC 是一种设计理念:对象的创建和管理由容器负责,而不是由程序自己 new。
Spring 容器就是实现 IoC 的具体工具。
当容器启动时:
扫描类(带注解的,比如 @Controller, @Service 等)
自动创建这些类的对象(实例化)
把对象存到 IoC 容器中 → 这就是“控制反转”:对象不由你主动创建,而是由容器管理。
2. 业务层:
业务层不关心请求,它只负责写业务逻辑,比如“转账”、“下订单”、“权限校验”。创建调用Service对象,即业务逻辑类的java类(比如校验账号密码), Service放在容器里(ApplicationContext),由容器统一管理,他还会创建调用DAO对象,DAO对象是专门访问数据库的类,调用DAO对象即调用持久层,因为dao对象都在持久层,dao会把返回结果给service,再传回web层
web层和业务层靠方法调用和依赖注入(DI/IoC)连接
1,方法调用
- Web 层(Servlet/Controller)收到请求后,会调用业务层(Service)的某个方法。
- 就像 Controller 是“前台”,它会说:
userService.login(username, password);
这里的 userService 就是业务层对象。
2.依赖注入(DI)
- Spring 框架会帮我们“装配”好 Controller 里需要的 Service。
- 比如:
@Controller
public class UserController {
@Autowired
private UserService userService; // Spring 自动注入
@PostMapping("/login")
public String login(String username, String password) {
return userService.login(username, password);
}
}
@Autowired 告诉 Spring:帮我把业务层对象放进来。
3. 数据访问层(DAO层)
负责与数据库交互,DAO = Data Access Object(数据访问对象),即是用@Repository标记的类
DAO 层的作用:
接收业务层(Service)的请求
负责执行 SQL(增删改查)
返回结果对象给业务层
为什么要有 DAO?
想象一下:
如果业务层(Service)直接写 SQL,会导致业务逻辑和数据库操作耦合,代码很乱。
有了 DAO:
业务层只关心“我要查某个用户”
DAO 负责“SQL 语句怎么写、JDBC 怎么连数据库”,这样就实现了 职责分离。
而Hibernate就是一个能大大简化这个过程的 ORM 框架。
ORM 即对象关系映射
意思是:
- 你在 Java 里用对象(Object)来写业务逻辑;
- 但数据最后要存到关系型数据库(MySQL、PostgreSQL 等)的表里;
- ORM 框架就帮你把对象和数据库表自动对应起来。
例如:User 类 对应users 表 , user.getName()对应数据库字段 name
我们不需要写sql了,直接用java写ORM对象及方法就可以实现
JSP、Action类、Servlet 在 MVC 框架里是怎么配合工作的 ?
Servlet + JSP
在最原始的 Java Web(没用框架)里:
浏览器请求 → Servlet
Servlet 接收请求,执行业务逻辑。
Servlet 处理完,把数据存进 request / session 域。
Servlet 转发 (forward) 给 JSP。
JSP 填充数据进入html模版(只是显示,不写业务逻辑)。
所以:Servlet 是控制器,JSP 是视图。
Struts2 的流程(Action)
浏览器请求 /login.action。
请求先经过前端控制器(Filter:StrutsPrepareAndExecuteFilter)。
Struts 找到对应的 Action 类(比如 LoginAction)。
执行一系列拦截器(Interceptor链) → 再执行 Action 的 execute() 方法。
Action 处理业务逻辑,返回一个字符串(如 "success")。
Struts2 根据返回值去找对应的结果视图(JSP)。
转发到 success.jsp,显示结果。
在 Struts2 里:
Action 类 = 控制器
JSP = 视图
Servlet(即 StrutsPrepareAndExecuteFilter 内部用到的 Servlet 技术)对开发者是“透明的”,不直接写。
Spring MVC 的流程(Controller)
浏览器请求 /login。
请求进入前端控制器 DispatcherServlet(这是一个 Servlet)。
DispatcherServlet 找到对应的 Controller 类(比如 LoginController)。
调用 Controller 的方法 → 方法返回一个 ModelAndView 或字符串(视图名)。
DispatcherServlet 把数据传给 视图解析器,找到 JSP。
JSP 渲染页面,返回给浏览器。
在 Spring MVC 里:
Controller 类 = 控制器
JSP = 视图
DispatcherServlet = Servlet 前端控制器
核心区别一句话
原始 Java Web:Servlet 直接当控制器。
Struts2:Action 类取代了 Servlet,当控制器。
Spring MVC:Controller 类取代了 Servlet,当控制器,但底层还是 DispatcherServlet 驱动。
ServletContext
ServletContext = Web 应用的全局上下文对象。
ServletContext 本身是接口(javax.servlet.ServletContext)。
Tomcat 之类的容器会给它提供一个实现类。
例如:Tomcat 里有 org.apache.catalina.core.ApplicationContext,它就是实现类。
当你在 Servlet 里调用 getServletContext(),得到的就是这个实现类的对象。
它在整个 Web 应用启动时由服务器(Tomcat)创建,一个 WebApp 只有一个 ServletContext。
用途:
-
- 存储全局属性(所有 servlet/jsp 都能访问)
- 获取资源路径(
getResourceAsStream("/WEB-INF/...")) - 拿容器信息(服务器版本、路径等)
server.xml
它是 Tomcat 的主配置文件,路径一般在 TOMCAT_HOME/conf/server.xml。
它定义了 整个服务器的组件结构:
- 端口(如 8080)
- Service(服务)
- Connector(连接器,负责监听端口、接收请求)
- Engine / Host / Context(不同层级的容器)
- 各种 Valve、Filter(过滤器/日志组件)
里面有一个类AccessLogValue,它专门用来写访问日志,在server.xml里大概长这样:
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
这里面有个suffix属性,是规定日志文件的后缀名的, AccessLogValve 会按日期(默认每天)切分日志文件。 更改后缀名后,会在下一次生成日志文件时生效
更多推荐

所有评论(0)