30个类手写Spring核心原理之MVC映射功能(4

if(isModelAndView){

return (GPModelAndView)result;

}else{

return null;

}

}

private Object caseStringValue(String value,Class<?> clazz){

if(clazz == String.class){

return value;

}else if(clazz == Integer.class){

return Integer.valueOf(value);

}else if(clazz == int.class){

return Integer.valueOf(value).intValue();

}else {

return null;

}

}

}

1.4 GPModelAndView

原生Spring中ModelAndView类主要用于封装页面模板和要往页面传送的参数的对应关系。

package com.tom.spring.formework.webmvc;

import java.util.Map;

public class GPModelAndView {

private String viewName; //页面模板的名称

private Map<String,?> model; //往页面传送的参数

public GPModelAndView(String viewName) {

this(viewName,null);

}

public GPModelAndView(String viewName, Map<String, ?> model) {

this.viewName = viewName;

this.model = model;

}

public String getViewName() {

return viewName;

}

public void setViewName(String viewName) {

this.viewName = viewName;

}

public Map<String, ?> getModel() {

return model;

}

public void setModel(Map<String, ?> model) {

this.model = model;

}

}

1.5 GPViewResolver

原生Spring中的ViewResolver主要完成模板名称和模板解析引擎的匹配。通过在Serlvet中调用resolveViewName()方法来获得模板所对应的View。在这个Mini版本中简化了实现,只实现了一套默认的模板引擎,语法也是完全自定义的。

package com.tom.spring.formework.webmvc;

import java.io.File;

import java.util.Locale;

//设计这个类的主要目的是:

//1. 将一个静态文件变为一个动态文件

//2. 根据用户传送不同的参数,产生不同的结果

//最终输出字符串,交给Response输出

public class GPViewResolver {

private final String DEFAULT_TEMPLATE_SUFFIX = “.html”;

private File templateRootDir;

private String viewName;

public GPViewResolver(String templateRoot){

String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot). getFile();

this.templateRootDir = new File(templateRootPath);

}

public GPView resolveViewName(String viewName, Locale locale) throws Exception {

this.viewName = viewName;

if(null == viewName || “”.equals(viewName.trim())){ return null;}

viewName = viewName.endsWith(DEFAULT_TEMPLATE_SUFFIX) ? viewName : (viewName + DEFAULT_TEMPLATE_SUFFIX);

File templateFile = new File((templateRootDir.getPath() + “/” + viewName).replaceAll (“/+”, “/”));

return new GPView(templateFile);

}

public String getViewName() {

return viewName;

}

}

1.6 GPView

这里的GPView就是前面所说的自定义模板解析引擎,其核心方法是render()。在render()方法中完成对模板的渲染,最终返回浏览器能识别的字符串,通过Response输出。

package com.tom.spring.formework.webmvc;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.RandomAccessFile;

import java.util.Map;

import java.io.File;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

public class GPView {

public static final String DEFAULT_CONTENT_TYPE = “text/html;charset=utf-8”;

private File viewFile;

public GPView(File viewFile){

this.viewFile = viewFile;

}

public String getContentType(){

return DEFAULT_CONTENT_TYPE;

}

public void render(Map<String, ?> model,HttpServletRequest request, HttpServletResponse response) throws Exception{

StringBuffer sb = new StringBuffer();

RandomAccessFile ra = new RandomAccessFile(this.viewFile,“r”);

try {

String line = null;

while (null != (line = ra.readLine())) {

line = new String(line.getBytes(“ISO-8859-1”),“utf-8”);

Pattern pattern = Pattern.compile(“¥\{[^\}]+\}”,Pattern.CASE_INSENSITIVE);

Matcher matcher = pattern.matcher(line);

while (matcher.find()) {

String paramName = matcher.group();

paramName = paramName.replaceAll(“¥\{|\}”,“”);

Object paramValue = model.get(paramName);

if (null == paramValue) { continue; }

//要把¥{}中间的这个字符串取出来

line = matcher.replaceFirst(makeStringForRegExp(paramValue.toString()));

matcher = pattern.matcher(line);

}

sb.append(line);

}

}finally {

ra.close();

}

response.setCharacterEncoding(“utf-8”);

//response.setContentType(DEFAULT_CONTENT_TYPE);

response.getWriter().write(sb.toString());

}

//处理特殊字符

public static String makeStringForRegExp(String str) {

return str.replace(“\”, “\\”).replace(“", "\”)

.replace(“+”, “\+”).replace(“|”, “\|”)

.replace(“{”, “\{”).replace(“}”, “\}”)

.replace(“(”, “\(”).replace(“)”, “\)”)

.replace(“^”, “\^”).replace(“$”, “\$”)

.replace(“[”, “\[”).replace(“]”, “\]”)

.replace(“?”, “\?”).replace(“,”, “\,”)

.replace(“.”, “\.”).replace(“&”, “\&”);

}

}

从上面的代码可以看出,GPView是基于HTML文件来对页面进行渲染的。但是加入了一些自定义语法,例如在模板页面中扫描到¥{name}这样的表达式,就会从ModelAndView的Model中找到name所对应的值,并且用正则表达式将其替换(外国人喜欢用美元符号$,我们的模板引擎就用人民币符号¥)。

2 业务代码实现


2.1 IQueryService

定义一个负责查询业务的顶层接口IQueryService,提供一个query()方法:

package com.tom.spring.demo.service;

/**

  • 查询业务

*/

public interface IQueryService {

/**

  • 查询

*/

public String query(String name);

}

2.2 QueryService

查询业务的实现QueryService也非常简单,就是打印一下调用时间和传入的参数,并封装为JSON格式返回:

package com.tom.spring.demo.service.impl;

import java.text.SimpleDateFormat;

import java.util.Date;

import com.tom.spring.demo.service.IQueryService;

import com.tom.spring.formework.annotation.GPService;

import lombok.extern.slf4j.Slf4j;

/**

  • 查询业务

*/

@GPService

@Slf4j

public class QueryService implements IQueryService {

/**

  • 查询

*/

public String query(String name) {

SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

String time = sdf.format(new Date());

String json = “{name:”" + name + “”,time:“” + time + “”}";

log.info(“这是在业务方法中打印的:” + json);

return json;

}

}

2.3 IModifyService

定义一个增、删、改业务的顶层接口IModifyService:

package com.tom.spring.demo.service;

/**

  • 增、删、改业务

*/

public interface IModifyService {

/**

  • 增加

*/

public String add(String name, String addr) ;

/**

  • 修改

*/

public String edit(Integer id, String name);

/**

  • 删除

*/

public String remove(Integer id);

}

2.4 ModifyService

增、删、改业务的实现ModifyService也非常简单,主要是打印传过来的参数:

package com.tom.spring.demo.service.impl;

import com.tom.spring.demo.service.IModifyService;

import com.tom.spring.formework.annotation.GPService;

/**

  • 增、删、改业务

*/

@GPService

public class ModifyService implements IModifyService {

/**

  • 增加

*/

public String add(String name,String addr) {

return “modifyService add,name=” + name + “,addr=” + addr;

}

/**

  • 修改

*/

public String edit(Integer id,String name) {

return “modifyService edit,id=” + id + “,name=” + name;

}

/**

  • 删除

*/

public String remove(Integer id) {

return “modifyService id=” + id;

}

}

2.5 MyAction

Controller的主要功能是负责调度,不做业务实现。业务实现方法全部在Service层,一般我们会将Service实例注入Controller。MyAction中主要实现对IQueryService和IModifyService的调度,统一返回结果:

package com.tom.spring.demo.action;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import com.tom.spring.demo.service.IModifyService;

import com.tom.spring.demo.service.IQueryService;

import com.tom.spring.formework.annotation.GPAutowired;

import com.tom.spring.formework.annotation.GPController;

import com.tom.spring.formework.annotation.GPRequestMapping;

import com.tom.spring.formework.annotation.GPRequestParam;

import com.tom.spring.formework.webmvc.GPModelAndView;

/**

  • 公布接口URL

*/

@GPController

@GPRequestMapping(“/web”)

public class MyAction {

@GPAutowired IQueryService queryService;

@GPAutowired IModifyService modifyService;

@GPRequestMapping(“/query.json”)

public GPModelAndView query(HttpServletRequest request, HttpServletResponse response,

@GPRequestParam(“name”) String name){

String result = queryService.query(name);

return out(response,result);

}

@GPRequestMapping(“/add*.json”)

public GPModelAndView add(HttpServletRequest request,HttpServletResponse response,

@GPRequestParam(“name”) String name,@GPRequestParam(“addr”) String addr){

String result = modifyService.add(name,addr);

return out(response,result);

}

@GPRequestMapping(“/remove.json”)

public GPModelAndView remove(HttpServletRequest request,HttpServletResponse response,

@GPRequestParam(“id”) Integer id){

String result = modifyService.remove(id);

return out(response,result);

}

@GPRequestMapping(“/edit.json”)

public GPModelAndView edit(HttpServletRequest request,HttpServletResponse response,

@GPRequestParam(“id”) Integer id,

@GPRequestParam(“name”) String name){

String result = modifyService.edit(id,name);

return out(response,result);

}

private GPModelAndView out(HttpServletResponse resp,String str){

try {

resp.getWriter().write(str);

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

}

2.6 PageAction

专门设计PageAction是为了演示Mini版Spring对模板引擎的支持,实现从Controller层到View层的传参,以及对模板的渲染进行最终输出:

package com.tom.spring.demo.action;

import java.util.HashMap;

import java.util.Map;

import com.tom.spring.demo.service.IQueryService;

import com.tom.spring.formework.annotation.GPAutowired;

import com.tom.spring.formework.annotation.GPController;

import com.tom.spring.formework.annotation.GPRequestMapping;

import com.tom.spring.formework.annotation.GPRequestParam;

import com.tom.spring.formework.webmvc.GPModelAndView;

/**

  • 公布接口URL

*/

@GPController

@GPRequestMapping(“/”)

public class PageAction {

@GPAutowired IQueryService queryService;

@GPRequestMapping(“/first.html”)

public GPModelAndView query(@GPRequestParam(“teacher”) String teacher){

String result = queryService.query(teacher);

Map<String,Object> model = new HashMap<String,Object>();

model.put(“teacher”, teacher);

model.put(“data”, result);

model.put(“token”, “123456”);

return new GPModelAndView(“first.html”,model);

}

}

3 定制模板页面


为了更全面地演示页面渲染效果,分别定义了first.html对应PageAction中的first.html请求、404.html默认页和500.html异常默认页。

3.1 first.html

first.html定义如下:

SpringMVC模板引擎演示

大家好,我是¥{teacher}老师
欢迎大家一起来探索Spring的世界

Hello,My name is ¥{teacher}

¥{data}

Token值:¥{token}

3.2 404.html

404.html定义如下:

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

.html

first.html定义如下:

SpringMVC模板引擎演示

大家好,我是¥{teacher}老师
欢迎大家一起来探索Spring的世界

Hello,My name is ¥{teacher}

¥{data}

Token值:¥{token}

3.2 404.html

404.html定义如下:

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-XOdG2tMN-1710778362795)]
[外链图片转存中…(img-W9nIpXkC-1710778362796)]
[外链图片转存中…(img-I3wrHgx3-1710778362796)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-2BKRsO6W-1710778362797)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值