1. Spring MVC
2. 三层架构

3. MVC
MVC(Model View Controller) 设计创建Web应用程序表现层的模式
- Model 模型 : 数据模型,用于封装数据
View 视图 : 页面视图,用于展示数据
- jsp
- html
Contoller 控制器 :处理用户交互的调度器,用于根据用户需求处理程序逻辑
- Servlet
4. 项目构建 xml
导入坐标
<!-- servlet3.1规范的坐标 --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!--jsp坐标--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.1</version><scope>provided</scope></dependency><!--spring web的坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.1.9.RELEASE</version></dependency><!--springmvc的坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency>
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.itheima"><!-- 包含以下注解则加载 --><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><!--放行指定类型静态资源配置方式--><!-- <mvc:resources mapping="/img/**" location="/img/"/>--><!-- <mvc:resources mapping="/js/**" location="/js/"/>--><!-- <mvc:resources mapping="/css/**" location="/css/"/>--><!--SpringMVC提供的通用资源放行方式 释放所有静态资源--><mvc:default-servlet-handler/></beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><!--乱码处理过滤器,与Servlet中使用的完全相同,差异之处在于处理器的类由Spring提供--><filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 扫描mvc配置文件 --><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath*:spring-mvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>
5. 技术架构图

6. 注解驱动
6.1. 扫描包含Controller注解的类
在springmvc 配置类中
@ComponentScan(value = "com.itheima",includeFilters =@ComponentScan.Filter(type=FilterType.ANNOTATION,classes = {Controller.class}))
6.2. 注解配置指定放行的资源
实现WebMvcConfigurer接口 重写addResourceHandlers方法
public class SpringMVCConfiguration implements WebMvcConfigurer{//注解配置放行指定资源格式@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/img/**").addResourceLocations("/img/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");}}
6.3. 注解配置放行所有静态资源
实现WebMvcConfigurer接口 重写configureDefaultServletHandling方法
public class SpringMVCConfiguration implements WebMvcConfigurer{@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();;}}
6.4. servlet扫描mvc配置文件
继承 AbstractDispatcherServletInitializer 类 重写里面的 createServletApplicationContext createRootApplicationContext 和 getServletMappings 方法
import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;import org.springframework.web.filter.CharacterEncodingFilter;import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;import javax.servlet.DispatcherType;import javax.servlet.FilterRegistration;import javax.servlet.ServletContext;import javax.servlet.ServletException;import java.util.EnumSet;public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {//创建Servlet容器时,使用注解的方式加载SPRINGMVC配置类中的信息,并加载成WEB专用的ApplicationContext对象//该对象放入了ServletContext范围,后期在整个WEB容器中可以随时获取调用@Overrideprotected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();//需要一个MVC配置类ctx.register(SpringMVCConfiguration.class);return ctx;}//注解配置映射地址方式,服务于SpringMVC的核心控制器DispatcherServlet@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}@Overrideprotected WebApplicationContext createRootApplicationContext() {return null;}//乱码处理作为过滤器,在servlet容器启动时进行配置,相关内容参看Servlet零配置相关课程@Overridepublic void onStartup(ServletContext servletContext) throws ServletException {super.onStartup(servletContext);CharacterEncodingFilter cef = new CharacterEncodingFilter();cef.setEncoding("UTF-8");FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", cef);registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST,DispatcherType.FORWARD,DispatcherType.INCLUDE),false,"/*");}}
7. 请求
7.1. 请求参数
SpringMVC将传递的参数封装到处理器方法的形参中,达到快速访问参数的目的
只需在形参上与请求地址上的参数名字一致 即可获取到请求参数的值
//请求参数 http://localhost/requestParam1?name=hello@RequestMapping("/requestParam1")public String requestParam1(String name){System.out.println(name);return "index.jsp";}
7.1.1. 普通类型
参数名与处理器方法形参名保持一致 否则无法获取对应的值
如果想要绑定具体的请求名 则需要使用 @RequestParam
-
- value 请求属性名
- required 不允许为空 默认为true
- defaultValue 为空时默认值
//请求参数形参绑定名 http://localhost/requestParam2?username=hello&age=10@RequestMapping("/requestParam2")public String requestParam2(@RequestParam(value = "username",required = true,defaultValue = "zhangsan") String name, int age){System.out.println(name);System.out.println(age);return "index.jsp";}
7.1.2. POJO类型
如果形参为一个对象 则请求参数会将值 一一对应为对象中属性值
//POJO类型参数 http://localhost/requestParam3?username=zhangsan&age=10@RequestMapping("/requestParam3")public String requestParam3(User user){System.out.println(user.toString());return "index.jsp";}
7.1.2.1. POJO类型与普通类型同时存在
将会被同时赋值 如果想进行区分 建议使用@RequestParam进行绑定
//POJO类型参数与普通类型同时存在 http://localhost/requestParam4?name=zhangsan&age=10@RequestMapping("/requestParam4")public String requestParam4(User user,String age){System.out.println(user.toString());System.out.println(age);return "index.jsp";}
7.1.2.2. 复杂POJO类型 嵌套
如果POJO中嵌套POJO则 需要请求地址 需要按照层次结构要书写
//复杂POJO类型 http://localhost/requestParam5?address.city=shanghai@RequestMapping("/requestParam5")public String requestParam5(User user){System.out.println(user.getAddress().getCity());return "index.jsp";}
7.1.2.3. 复杂POJO类型 集合
如果POJO中出现集合 保存简单数据 使用多个相同名称的参数为其进行赋值
//复杂POJO类型 集合 http://localhost/requestParam6?nick=zhangsan&nick=lisi&nick=wangwu@RequestMapping("/requestParam6")public String requestParam6(User user){System.out.println(user);return "index.jsp";}
7.1.2.4. 复杂POJO类型 集合对象
集合对象 以索引形式的请求地址
//复杂POJO类型 集合对象 http://localhost/requestParam7?addresses[0].province=bj&addresses[1].province=gd@RequestMapping("/requestParam7")public String requestParam7(User user){System.out.println(user.getAddresses());return "index.jsp";}
7.1.2.5. 复杂POJO类型 Map集合
Map集合 在请求地址中以 key的形式赋值
//复杂POJO类型 集合对象 http://localhost/requestParam8?addressMap['home'].province=bj&addressMap['job'].province=gd@RequestMapping("/requestParam8")public String requestParam8(User user){System.out.println(user.getAddressMap());return "index.jsp";}
7.1.3. 数组类型
请求参数名与数组名一致 并请求参数数量大于1个
//数组类型 http://localhost/requestParam9?nick=abc&nick=def@RequestMapping("/requestParam9")public String requestParam9(String[] nick) {System.out.println(nick[0] + " " + nick[1]);return "index.jsp";}
7.1.4. 集合类型
MVC默认将list作为对象处理 赋值前先创建对象 然后将nick作为对象的属性赋值 但list是接口 无法创建对象 和 有此属性值 所以报错
我们通过@RequestParam 将请求参数打包成数组
//集合类型 http://localhost/requestParam10?nick=abc&nick=def@RequestMapping("/requestParam10")public String requestParam10(@RequestParam("nick") List<String> nick) {System.out.println(nick);return "index.jsp";}
7.2. 类型转换器
MVC对接受的数据进行自动类型转换 通过Converter接口实现
7.2.1. xml 日期类型格式转换
spring默认的日期格式为 2021/09/11 如果我们传递为2021-09-11则会报错 我们需要自定义日期格式转换
<!-- 自定义转换格式--><mvc:annotation-driven conversion-service="conversionService"/><!-- 注册bean 让spring管理--><bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="formatters"><set><bean class="org.springframework.format.datetime.DateFormatter"><property name="pattern" value="yyyy-MM-dd"/></bean></set></property></bean>
7.2.2. 注解版 日期类型格式转换
//日期类型 自定义格式转换 http://localhost/requestParam11?date=2021-09-11@RequestMapping("/requestParam11")public String requestParam11(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {System.out.println(date);return "index.jsp";}
并开启mvc注解驱动
<mvc:annotation-driven />
7.2.3. 自定义类型转换器
实现 Converter 接口 泛型1为原始数据类型 泛型2为返回的数据类型 并实现 convert 方法
<!-- 自定义类型转换器--><mvc:annotation-driven conversion-service="conversionService"/><!-- 注册bean 让spring管理--><bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><set><bean class="com.itheima.converter.MyDateConverter"></bean></set></property></bean>
处理类
import org.springframework.core.convert.converter.Converter;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class MyDateConverter implements Converter<String, Date> {@Overridepublic Date convert(String s) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date date = null;try {date = simpleDateFormat.parse(s);} catch (ParseException e) {e.printStackTrace();}return date;}}
7.3. 请求映射
- @RequestMapping 设置在方法上则是方法体的请求映射 定义在类上则是整个类的访问前缀
- value 请求路径
- method = RequestMethod.GET 请求方式
- params = “name” 请求地址必须传递此属性才能访问
- headers = “content-type=text/*” 请求头条件
- consumes = “text/*” 可以接受的请求正文类型
- produces = “text/*” 可以生成的响应正文类型
8. 响应
8.1. 页面跳转方式
- 转发(默认)
@RequestMapping("/showPageAndData1")public String showPageAndData1(HttpServletRequest request){return "forward:success.jsp";}
- 重定向
@RequestMapping("/showPageAndData7")public String showPageAndData7(){return "redirect:index.jsp";}
- 页面访问快捷设定 设置了快捷访问 后默认访问是设定的路径下制定的后缀文件 默认为转发跳转 无法重定向
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/page/"/><property name="suffix" value=".jsp"/></bean>
如果方法体没有返回值 也配置了快捷方式 则自动跳转到指定的路径下 访问路径 + 后缀 的文件

8.2. request传递数据
@RequestMapping("/showPageAndData1")public String showPageAndData1(HttpServletRequest request){request.setAttribute("name","hello");return "success.jsp";}
8.3. Model 类型形参进行数据传递
@RequestMapping("/showPageAndData2")public String showPageAndData2(Model model){model.addAttribute("name","hello");User user =new User();user.setAge(156);//可以传递对象model.addAttribute("user",user);return "success.jsp";}
8.4. ModelAndView 类型传递
@RequestMapping("/showPageAndData3")public ModelAndView showPageAndData3(ModelAndView modelAndView){modelAndView.addObject("name","hello");User user =new User();user.setAge(156);//添加属性modelAndView.addObject("user",user);//跳转页面modelAndView.setViewName("success.jsp");return modelAndView;}
8.4.1. 重定向
@RequestMapping("/showPageAndData5")public ModelAndView showPageAndData5(ModelAndView modelAndView){//重定向modelAndView.setViewName("redirect:index.jsp");return modelAndView;}@RequestMapping("/showPageAndData6")public ModelAndView showPageAndData6(ModelAndView modelAndView){//跳转modelAndView.setViewName("forward:index.jsp");return modelAndView;}
8.5. 返回JSON数据
响应方法体 返回的数据默认会直接跳转到 返回值对应的页面文件
我们可以在方法体上 加上 @ResponseBody 注解 来声明为一个响应体
@RequestMapping("showData1")@ResponseBodypublic String showData1() throws JsonProcessingException {User user = new User();user.setAge(15);user.setName("zhangsan");ObjectMapper om = new ObjectMapper();return om.writeValueAsString(user);}
- 返回一个对象或者集合 Jackson 已经帮我们做好了 自定义类型转换了 我们只需要在spring配置中开启注解驱动 即可
<mvc:annotation-driven />
注解版 开启注解驱动 为 @EnableWebMvc
@RequestMapping("showData2")@ResponseBodypublic User showData2() throws JsonProcessingException {User user = new User();user.setAge(15);user.setName("zhangsan");return user;}
9. Servlet相关接口
原始的 request response 和 session 提供给我们使用但是不太推荐使用原生的功能

9.1. Head数据获取
- @RequestHeader 获取头中指定的值
@RequestMapping("/headApi")public String headApi(@RequestHeader("Accept-Language") String head){System.out.println(head);return "index.jsp";}
9.2. Cookie 数据获取
- @CookieValue 获取cookie指定key的值
@RequestMapping("/cookieApi")public String cookieApi(@CookieValue("_xsrf") String cookie){System.out.println(cookie);return "index.jsp";}
9.3. Session 数据获取和设置
设置 只有在类注解上方标记的变量名称才会被放到session中
获取
@RequestMapping("/sessionApi")public String sessionApi(@SessionAttribute("name") String session){System.out.println(session);return "index.jsp";}
10. 发送异步请求
通过ajax发送的异步请求 是无法直接被赋值给形参的 需要在形参前面 加上 @RequestBody
@RequestMapping("/ajax1")public String ajax1(@RequestBody String data) {System.out.println(data);return "index.jsp";}
JSON转POJO 会自动赋值给POJO中属性
@RequestMapping("/ajax2")public String ajax2(@RequestBody User user) {System.out.println(user);return "index.jsp";}
集合
@RequestMapping("/ajax3")public String ajax3(@RequestBody List<User> user) {System.out.println(user);return "index.jsp";}
11. 异步请求响应
返回字符串
@RequestMapping("/ajax4")@ResponseBodypublic String ajax4() {return "hello";}
返回对象
@RequestMapping("/ajax5")@ResponseBodypublic User ajax5() {User user = new User();user.setName("hhh");user.setAge(13);return user;}
返回集合
@RequestMapping("/ajax6")@ResponseBodypublic List ajax6() {User user = new User();User user2 = new User();user.setName("hhh");user.setAge(13);user2.setName("qqqq");user2.setAge(17);ArrayList<User> arrayList = new ArrayList<>();arrayList.add(user);arrayList.add(user2);return arrayList;}
12. 跨域访问
当通过A域名下的操作访问 域名B下的资源时 称为跨域访问
我们可以通过设置头信息 开启跨域访问限制
但spring 帮我完成这个操作 我们只需要添加@CrossOrigin 就可以解决 定义在方法体或类上
@RequestMapping("/cross")@ResponseBody@CrossOriginpublic void cross() {}
13. 拦截器
拦截器(Interceptor) 是一种动态拦截方法调用的机制
- 在指定的方法调用前后执行预先设定后的代码
- 阻止原始方法的执行
核心原理:AOP思想
拦截器链:多个拦截器按照一定的顺序 对原始被调用功能进行增强
实现 HandlerInterceptor 接口 重写需要的方法
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("前置运行");//如果为false 则直接拦截业务处理器不放行return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("后置运行");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("完成运行");}}
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/handleRun"/><bean class="com.itheima.interceptor.MyInterceptor"/></mvc:interceptor></mvc:interceptors>

13.1. 拦截器参数
- request 请求对象
- response 响应对象
- handler 被调用的处理器对象,对反射中的method对象进行了包装
- ModelAndView 可以读取或者修改 页面信息和对应数据
- Exception 如果处理器执行中出现异常 如何处理
13.2. 多个拦截器
多个拦截器执行顺序与xml配置有关
但多个拦截器中的前置运行 后置运行 都会同时启用
按照链式 执行顺序

13.3. 责任链模式

14. 异常处理
类注解 @Component 绑定Bean为 并实现 HandlerExceptionResolver 接口 实现方法
此bean会拦截mvc上请求的异常
@Componentpublic class ExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {System.out.println("发生异常了");ModelAndView modelAndView =new ModelAndView();if(e instanceof NullPointerException){//添加错误信息modelAndView.addObject("msg","空指针异常");}else if (e instanceof ArithmeticException){//添加错误信息modelAndView.addObject("msg","算术异常");}else {//添加错误信息modelAndView.addObject("msg","未知异常");}//转发页面modelAndView.setViewName("error.jsp");return modelAndView;}}
14.1. 注解版异常处理
- @ExceptionHandler 注解 标记要捕抓的异常
@Component@ControllerAdvicepublic class ExceptionAdivce {//异常 的类@ExceptionHandler(NullPointerException.class)@ResponseBodypublic String doNullException(Exception e){System.out.println("空指针异常");return "空指针异常";}//异常 的类@ExceptionHandler(ArithmeticException.class)@ResponseBodypublic String doArithmeticException(Exception e){System.out.println("算术异常");return "算术异常";}//异常 的类@ExceptionHandler(Exception.class)@ResponseBodypublic String doException(Exception e){System.out.println("all");return "all";}}
注意事项:
@ExceptionHandler 注解 会比 HandlerExceptionResolver 运行早
HandlerExceptionResolver 无法捕抓到参数异常 而注解可以捕抓到
15. 文件上传下载
坐标
<!--文件上传下载--><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version></dependency>

上传文件传递的name 要与 形参的名称一致
16. Restful


16.1. PathVariable
@PathVariable 为Restful 规范的请求路径 赋值给指定形参
并且在@RequestMapping 的 method 指定请求方式
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)public String restLocation(@PathVariable Integer id){System.out.println(id);return "page.jsp";}
16.2. RestController
@RestController 结合了 @Controller和@ResponseBody 两个注解的功能
绑定为bean 并且 所有返回内容都不会解析为网页结构
16.3. XXXMapping
如 @GetMapping @PostMapping 请求等等
我们不用在@RequestMapping 中定义指定的请求方式 和 请求路径
只需在方法体加上指定请求方式的注解即
@PostMapping("{id}")public String postrestLocation(@PathVariable Integer id){System.out.println(id);return "page.jsp";}
17. 表单验证框架
Hibernate框架
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>6.1.0.Final</version></dependency>
- @Valid 形参注解 开启此形参的验证
- @Valid 属性注解 开启此对象或属性验证 对象校验在对象内部属性定义规则
- @NotBlank(message = “提醒信息”) 属性验证规则 不能为null 并且长度必须大于0和不全为空格 则不能为空
- @NotNull (message = “提醒信息”) 不能为null 可以为空
- @NotEmpty(message = “”) 不能为空和null
- @Max(value = “” , message =” “) 限定最大值
- @Min(value = “” , message = “”) 最小值
- @Range(max = ,min = ,message = ) 最大最小值
@RequestMapping(value = "/addemployee2")//使用@Valid开启校验,使用@Validated也可以开启校验//Errors对象用于封装校验结果,如果不满足校验规则,对应的校验结果封装到该对象中,包含校验的属性名和校验不通过返回的消息public String addEmployee2(@Valid Employee employee, Errors errors, Model m){//判定Errors对象中是否存在未通过校验的字段if(errors.hasErrors()){//获取所有未通过校验规则的信息List<FieldError> fieldErrors = errors.getFieldErrors();System.out.println(fieldErrors.size());for(FieldError error : fieldErrors){System.out.println(error.getField());System.out.println(error.getDefaultMessage());//将校验结果信息添加到Model对象中,用于页面显示,后期实际开发中无需这样设定,返回json数据即可m.addAttribute(error.getField(),error.getDefaultMessage());}//当出现未通过校验的字段时,跳转页面到原始页面,进行数据回显return "addemployee.jsp";}return "success.jsp";}
@NotBlank(message = "姓名不能为空")private String name;//员工姓名//一个属性可以添加多个校验器@NotNull(message = "请输入您的年龄")@Max(value = 60,message = "年龄最大值不允许超过60岁")@Min(value = 18,message = "年龄最小值不允许低于18岁")private Integer age;//员工年龄//实体类中的引用类型通过标注@Valid注解,设定开启当前引用类型字段中的属性参与校验@Validprivate Address address;
17.1. 分组校验
如果不开启分组校验 则会校验当前全部开启校验的属性/对象
在属性/对象校验注解中 加上 groups 属性 并给予一个 用于标识的字节码文件
//设定校验器,设置校验不通过对应的消息,设定所参与的校验组@NotBlank(message = "姓名不能为空",groups = {GroupA.class})private String name;//员工姓名
拦截校验器 开启校验注解要改为 @Validated 并加上标识字节码文件
@RequestMapping(value = "/addemployee")public String addEmployee(@Validated({GroupA.class}) Employee employee, Errors errors, Model m){if(errors.hasErrors()){List<FieldError> fieldErrors = errors.getFieldErrors();System.out.println(fieldErrors.size());for(FieldError error : fieldErrors){System.out.println(error.getField());System.out.println(error.getDefaultMessage());m.addAttribute(error.getField(),error.getDefaultMessage());}return "addemployee.jsp";}return "success.jsp";}
18. SSM
Spring + SpringMVC + MyBatis

