手寫Spring之spring初體驗V1版本
1.目標
在手寫最基礎的V1版本Spring之後,再次學習Spring中的核心源碼,提取出Spring中核心的IoC、DI、MVC、AOP各組件的的分工,自己用代碼手寫完成這些組件。
2.基本思路
IoC,DI思路總結:
1.調用Servlet init()方法,創建ApplicationContext
2.讀取配置文件(peoperties、xml、yml)
3.BeanDefinitionReader解析配置文件,掃描相關的類,封裝成BeanDefinition保存到了內存中
4.在ApplicationContext.getBean後,初始化IOC容器,並且實例化對象,封裝成BeanWrapper。
5.完成DI注入
MVC思路總結
1.初始化九大組件之HandlerMapping:讀取所有的RequestMapping中的url結合instance、Method緩存到HandlerMapping
2.初始化九大組件之HandlerAdapter:爲每個HandlerMapping創建一個HandlerAdapter(目前其實沒有適配改變內容)並緩存
3.初始化九大組件之ViewResolver:讀取配置文件的模板根目錄。
AOP思路總結
1.在IoC初始化所有類時,創建GPAdvisedSupport,讀取AopConfig配置文件。
2.GPAdvisedSupport中解析配置文件,使用正則匹配,創建method - Advices對應緩存。
3.,匹配aop類,創建Proxy類替代原類初始化,在Proxy類中,讀取method - Advices緩存,調用對應的advice方法。
3.源碼實現
PS.說明
源碼實現部分由於在編寫代碼時,可能在同一個類中不斷新增一些代碼,所以並不是以編寫順序排序。
3.1.自定義配置 application.properties 文件
爲了解析方便,我們用application.properties來代替application.xml文 件 ,具體配置內容如下:
#託管的類掃描包路徑#
scanPackage=com.gupaoedu.vip.demo
templateRoot=layouts
#切面表達式expression#
pointCut=public .* com.gupaoedu.vip.demo.service..*Service..*(.*)
#切面類
aspectClass=com.gupaoedu.vip.demo.aspect.LogAspect
#前置通知回調方法
aspectBefore=before
#後置通知回調方法
aspectAfter=after
#異常通知回調方法
aspectAfterThrow=afterThrowing
#異常類型捕獲
aspectAfterThrowingName=java.lang.Exception
3.2.配置web.xml文件
大家都知道,所有依賴於web容器的項目,都是從讀取web.xml文件開始的。我們先配置好web.xml
中的內容。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>Gupao Web Application</display-name>
<servlet>
<servlet-name>gpmvc</servlet-name>
<servlet-class>com.gupaoedu.vip.spring.framework.webmvc.servlet.GPDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>application.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>gpmvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
其中GPDispatcherServlet是有自己模擬Spring實現的核心功能類。
3.3自定義 Annotation
3.3.1 @GPService 註解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPService {
String value() default "";
}
3.3.2 @GPAutowired 注 解 :
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPAutowired {
String value() default "";
}
3.3.3 @GPController 注 解 :
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPController {
String value() default "";
}
3.3.4 @GPRequestMapping 注 解 :
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPRequestMapping {
String value() default "";
}
3.3.5 @GPRequestParam 注 解 :
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GPRequestParam {
String value() default "";
}
3.4 IoC、DI部分
3.4.1 GPBeanDefinition
public class GPBeanDefinition {
private String factoryBeanName;
private String beanClassName;
public String getFactoryBeanName() {
return factoryBeanName;
}
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
}
}
3.4.2 GPBeanDefinitionReader
public class GPBeanDefinitionReader {
//保存掃描的結果
private List<String> regitryBeanClasses = new ArrayList<String>();
private Properties contextConfig = new Properties();
public GPBeanDefinitionReader(String... configLocations) {
doLoadConfig(configLocations[0]);
//掃描配置文件中的配置的相關的類
doScanner(contextConfig.getProperty("scanPackage"));
}
public Properties getConfig(){
return this.contextConfig;
}
public List<GPBeanDefinition> loadBeanDefinitions() {
List<GPBeanDefinition> result = new ArrayList<GPBeanDefinition>();
try {
for (String className : regitryBeanClasses) {
Class<?> beanClass = Class.forName(className);
if(beanClass.isInterface()){continue;}
//保存類對應的ClassName(全類名)
//還有beanName
//1、默認是類名首字母小寫
result.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()), beanClass.getName()));
//2、自定義
//3、接口注入
for (Class<?> i : beanClass.getInterfaces()) {
result.add(doCreateBeanDefinition(i.getName(),beanClass.getName()));
}
}
}catch (Exception e){
e.printStackTrace();
}
return result;
}
private GPBeanDefinition doCreateBeanDefinition(String beanName, String beanClassName) {
GPBeanDefinition beanDefinition = new GPBeanDefinition();
beanDefinition.setFactoryBeanName(beanName);
beanDefinition.setBeanClassName(beanClassName);
return beanDefinition;
}
private void doLoadConfig(String contextConfigLocation) {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation.replaceAll("classpath:",""));
try {
contextConfig.load(is);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null != is){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void doScanner(String scanPackage) {
//jar 、 war 、zip 、rar
URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
File classPath = new File(url.getFile());
//當成是一個ClassPath文件夾
for (File file : classPath.listFiles()) {
if(file.isDirectory()){
doScanner(scanPackage + "." + file.getName());
}else {
if(!file.getName().endsWith(".class")){continue;}
//全類名 = 包名.類名
String className = (scanPackage + "." + file.getName().replace(".class", ""));
//Class.forName(className);
regitryBeanClasses.add(className);
}
}
}
//自己寫,自己用
private String toLowerFirstCase(String simpleName) {
char [] chars = simpleName.toCharArray();
// if(chars[0] > )
chars[0] += 32;
return String.valueOf(chars);
}
}
3.4.3 GPBeanWrapper
public class GPBeanWrapper {
private Object wrapperInstance;
private Class<?> wrappedClass;
public GPBeanWrapper(Object instance) {
this.wrapperInstance = instance;
this.wrappedClass = instance.getClass();
}
public Object getWrapperInstance() {
return wrapperInstance;
}
public Class<?> getWrappedClass() {
return wrappedClass;
}
}
3.5 MVC部分
3.5.1 HandlerMapping
public class GPHandlerMapping {
private Pattern pattern; //URL
private Method method; //對應的Method
private Object controller;//Method對應的實例對象
public GPHandlerMapping(Pattern pattern, Object controller, Method method) {
this.pattern = pattern;
this.method = method;
this.controller = controller;
}
public Pattern getPattern() {
return pattern;
}
public void setPattern(Pattern pattern) {
this.pattern = pattern;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object getController() {
return controller;
}
public void setController(Object controller) {
this.controller = controller;
}
}
3.5.2 GPHandlerAdapter
public class GPHandlerAdapter {
public GPModelAndView handler(HttpServletRequest req, HttpServletResponse resp, GPHandlerMapping handler) throws Exception{
//保存形參列表
//將參數名稱和參數的位置,這種關係保存起來
Map<String,Integer> paramIndexMapping = new HashMap<String, Integer>();
//通過運行時的狀態去拿到你
Annotation[] [] pa = handler.getMethod().getParameterAnnotations();
for (int i = 0; i < pa.length ; i ++) {
for(Annotation a : pa[i]){
if(a instanceof GPRequestParam){
String paramName = ((GPRequestParam) a).value();
if(!"".equals(paramName.trim())){
// String value = Arrays.toString(params.get(paramName))
// .replaceAll("\\[|\\]","")
// .replaceAll("\\s+",",");
// paramValues[i] = value;
paramIndexMapping.put(paramName,i);
}
}
}
}
//初始化一下
Class<?> [] paramTypes = handler.getMethod().getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
Class<?> paramterType = paramTypes[i];
if(paramterType == HttpServletRequest.class || paramterType == HttpServletResponse.class){
paramIndexMapping.put(paramterType.getName(),i);
}
}
//去拼接實參列表
//http://localhost/web/query?name=Tom&Cat
Map<String,String[]> params = req.getParameterMap();
Object [] paramValues = new Object[paramTypes.length];
for (Map.Entry<String,String[]> param : params.entrySet()) {
String value = Arrays.toString(params.get(param.getKey()))
.replaceAll("\\[|\\]","")
.replaceAll("\\s+",",");
if(!paramIndexMapping.containsKey(param.getKey())){continue;}
int index = paramIndexMapping.get(param.getKey());
//允許自定義的類型轉換器Converter
paramValues[index] = castStringValue(value,paramTypes[index]);
}
if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){
int index = paramIndexMapping.get(HttpServletRequest.class.getName());
paramValues[index] = req;
}
if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){
int index = paramIndexMapping.get(HttpServletResponse.class.getName());
paramValues[index] = resp;
}
Object result = handler.getMethod().invoke(handler.getController(),paramValues);
if(result == null || result instanceof Void){return null;}
boolean isModelAndView = handler.getMethod().getReturnType() == GPModelAndView.class;
if(isModelAndView){
return (GPModelAndView)result;
}
return null;
}
private Object castStringValue(String value, Class<?> paramType) {
if(String.class == paramType){
return value;
}else if(Integer.class == paramType){
return Integer.valueOf(value);
}else if(Double.class == paramType){
return Double.valueOf(value);
}else {
if(value != null){
return value;
}
return null;
}
}
}
3.5.3 GPView
public class GPView {
private File viewFile;
public GPView(File templateFile) {
this.viewFile = templateFile;
}
public void render(Map<String, ?> model, HttpServletRequest req, HttpServletResponse resp) throws Exception {
StringBuffer sb = new StringBuffer();
RandomAccessFile ra = new RandomAccessFile(this.viewFile,"r");
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);
line = matcher.replaceFirst(makeStringForRegExp(paramValue.toString()));
matcher = pattern.matcher(line);
}
sb.append(line);
}
resp.setCharacterEncoding("utf-8");
resp.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("&", "\\&");
}
}
3.5.4 GPModelAndView
public class GPModelAndView {
private String viewName;
private Map<String,?> model;
public GPModelAndView(String viewName, Map<String, ?> model) {
this.viewName = viewName;
this.model = model;
}
public GPModelAndView(String viewName) {
this.viewName = viewName;
}
public String getViewName() {
return viewName;
}
public Map<String, ?> getModel() {
return model;
}
}
3.5.5 GPViewResolver
public class GPViewResolver {
private final String DEFAULT_TEMPLATE_SUFFIX = ".html";
private File tempateRootDir;
public GPViewResolver(String templateRoot) {
String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();
tempateRootDir = new File(templateRootPath);
}
public GPView resolveViewName(String viewName){
if(null == viewName || "".equals(viewName.trim())){return null;}
viewName = viewName.endsWith(DEFAULT_TEMPLATE_SUFFIX)? viewName : (viewName + DEFAULT_TEMPLATE_SUFFIX);
File templateFile = new File((tempateRootDir.getPath() + "/" + viewName).replaceAll("/+","/"));
return new GPView(templateFile);
}
}
3.6 AOP部分
3.6.1 GPAopConfig
@Data
public class GPAopConfig {
private String pointCut;
private String aspectClass;
private String aspectBefore;
private String aspectAfter;
private String aspectAfterThrow;
private String aspectAfterThrowingName;
}
3.6.2 GPAdvice
@Data
public class GPAdvice {
private Object aspect;
private Method adviceMethod;
private String throwName;
public GPAdvice(Object aspect, Method adviceMethod) {
this.aspect = aspect;
this.adviceMethod = adviceMethod;
}
}
3.6.3 GPAdvisedSupport
/**
* 解析AOP配置的工具類
*/
public class GPAdvisedSupport {
private GPAopConfig config;
private Object target;
private Class targetClass;
private Pattern pointCutClassPattern;
private Map<Method,Map<String,GPAdvice>> methodCache;
public GPAdvisedSupport(GPAopConfig config) {
this.config = config;
}
//解析配置文件的方法
private void parse() {
//把Spring的Excpress變成Java能夠識別的正則表達式
String pointCut = config.getPointCut()
.replaceAll("\\.", "\\\\.")
.replaceAll("\\\\.\\*", ".*")
.replaceAll("\\(", "\\\\(")
.replaceAll("\\)", "\\\\)");
//保存專門匹配Class的正則
String pointCutForClassRegex = pointCut.substring(0, pointCut.lastIndexOf("\\(") - 4);
pointCutClassPattern = Pattern.compile("class " + pointCutForClassRegex.substring(pointCutForClassRegex.lastIndexOf(" ") + 1));
//享元的共享池
methodCache = new HashMap<Method, Map<String, GPAdvice>>();
//保存專門匹配方法的正則
Pattern pointCutPattern = Pattern.compile(pointCut);
try{
Class aspectClass = Class.forName(this.config.getAspectClass());
Map<String,Method> aspectMethods = new HashMap<String, Method>();
for (Method method : aspectClass.getMethods()) {
aspectMethods.put(method.getName(),method);
}
for (Method method : this.targetClass.getMethods()) {
String methodString = method.toString();
if(methodString.contains("throws")){
methodString = methodString.substring(0,methodString.lastIndexOf("throws")).trim();
}
Matcher matcher = pointCutPattern.matcher(methodString);
if(matcher.matches()){
Map<String,GPAdvice> advices = new HashMap<String, GPAdvice>();
if(!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))){
advices.put("before",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectBefore())));
}
if(!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))){
advices.put("after",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfter())));
}
if(!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))){
GPAdvice advice = new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfterThrow()));
advice.setThrowName(config.getAspectAfterThrowingName());
advices.put("afterThrow",advice);
}
//跟目標代理類的業務方法和Advices建立一對多個關聯關係,以便在Porxy類中獲得
methodCache.put(method,advices);
}
}
}catch(Exception e){
e.printStackTrace();
}
}
//根據一個目標代理類的方法,獲得其對應的通知
public Map<String,GPAdvice> getAdvices(Method method, Object o) throws Exception {
//享元設計模式的應用
Map<String,GPAdvice> cache = methodCache.get(method);
if(null == cache){
Method m = targetClass.getMethod(method.getName(),method.getParameterTypes());
cache = methodCache.get(m);
this.methodCache.put(m,cache);
}
return cache;
}
//給ApplicationContext首先IoC中的對象初始化時調用,決定要不要生成代理類的邏輯
public boolean pointCutMath() {
return pointCutClassPattern.matcher(this.targetClass.toString()).matches();
}
public void setTargetClass(Class<?> targetClass) {
this.targetClass = targetClass;
parse();
}
public void setTarget(Object target) {
this.target = target;
}
public Class getTargetClass() {
return targetClass;
}
public Object getTarget() {
return target;
}
}
3.6.4 GPJdkDynamicAopProxy
public class GPJdkDynamicAopProxy implements InvocationHandler {
private GPAdvisedSupport config;
public GPJdkDynamicAopProxy(GPAdvisedSupport config) {
this.config = config;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Map<String,GPAdvice> advices = config.getAdvices(method,null);
Object returnValue;
try {
invokeAdivce(advices.get("before"));
returnValue = method.invoke(this.config.getTarget(),args);
invokeAdivce(advices.get("after"));
}catch (Exception e){
invokeAdivce(advices.get("afterThrow"));
throw e;
}
return returnValue;
}
private void invokeAdivce(GPAdvice advice) {
try {
advice.getAdviceMethod().invoke(advice.getAspect());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),this.config.getTargetClass().getInterfaces(),this);
}
}
3.7 實現GPDispatcherServlet.java
/**
* 委派模式
* 職責:負責任務調度,請求分發
*/
public class GPDispatcherServlet extends HttpServlet {
private GPApplicationContext applicationContext;
private List<GPHandlerMapping> handlerMappings = new ArrayList<GPHandlerMapping>();
private Map<GPHandlerMapping,GPHandlerAdapter> handlerAdapters = new HashMap<GPHandlerMapping, GPHandlerAdapter>();
private List<GPViewResolver> viewResolvers = new ArrayList<GPViewResolver>();
@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 {
//6、委派,根據URL去找到一個對應的Method並通過response返回
try {
doDispatch(req,resp);
} catch (Exception e) {
try {
processDispatchResult(req,resp,new GPModelAndView("500"));
} catch (Exception e1) {
e1.printStackTrace();
resp.getWriter().write("500 Exception,Detail : " + Arrays.toString(e.getStackTrace()));
}
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
//完成了對HandlerMapping的封裝
//完成了對方法返回值的封裝ModelAndView
//1、通過URL獲得一個HandlerMapping
GPHandlerMapping handler = getHandler(req);
if(handler == null){
processDispatchResult(req,resp,new GPModelAndView("404"));
return;
}
//2、根據一個HandlerMaping獲得一個HandlerAdapter
GPHandlerAdapter ha = getHandlerAdapter(handler);
//3、解析某一個方法的形參和返回值之後,統一封裝爲ModelAndView對象
GPModelAndView mv = ha.handler(req,resp,handler);
// 就把ModelAndView變成一個ViewResolver
processDispatchResult(req,resp,mv);
}
private GPHandlerAdapter getHandlerAdapter(GPHandlerMapping handler) {
if(this.handlerAdapters.isEmpty()){return null;}
return this.handlerAdapters.get(handler);
}
private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, GPModelAndView mv) throws Exception {
if(null == mv){return;}
if(this.viewResolvers.isEmpty()){return;}
for (GPViewResolver viewResolver : this.viewResolvers) {
GPView view = viewResolver.resolveViewName(mv.getViewName());
//直接往瀏覽器輸出
view.render(mv.getModel(),req,resp);
return;
}
}
private GPHandlerMapping getHandler(HttpServletRequest req) {
if(this.handlerMappings.isEmpty()){return null;}
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replaceAll(contextPath,"").replaceAll("/+","/");
for (GPHandlerMapping mapping : handlerMappings) {
Matcher matcher = mapping.getPattern().matcher(url);
if(!matcher.matches()){continue;}
return mapping;
}
return null;
}
@Override
public void init(ServletConfig config) throws ServletException {
//初始化Spring核心IoC容器
applicationContext = new GPApplicationContext(config.getInitParameter("contextConfigLocation"));
//完成了IoC、DI和MVC部分對接
//初始化九大組件
initStrategies(applicationContext);
System.out.println("GP Spring framework is init.");
}
private void initStrategies(GPApplicationContext context) {
// //多文件上傳的組件
// initMultipartResolver(context);
// //初始化本地語言環境
// initLocaleResolver(context);
// //初始化模板處理器
// initThemeResolver(context);
//handlerMapping
initHandlerMappings(context);
//初始化參數適配器
initHandlerAdapters(context);
// //初始化異常攔截器
// initHandlerExceptionResolvers(context);
// //初始化視圖預處理器
// initRequestToViewNameTranslator(context);
//初始化視圖轉換器
initViewResolvers(context);
// //FlashMap管理器
// initFlashMapManager(context);
}
private void initViewResolvers(GPApplicationContext context) {
String templateRoot = context.getConfig().getProperty("templateRoot");
String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();
File templateRootDir = new File(templateRootPath);
for (File file : templateRootDir.listFiles()) {
this.viewResolvers.add(new GPViewResolver(templateRoot));
}
}
private void initHandlerAdapters(GPApplicationContext context) {
for (GPHandlerMapping handlerMapping : handlerMappings) {
this.handlerAdapters.put(handlerMapping,new GPHandlerAdapter());
}
}
private void initHandlerMappings(GPApplicationContext context) {
if(this.applicationContext.getBeanDefinitionCount() == 0){ return;}
for (String beanName : this.applicationContext.getBeanDefinitionNames()) {
Object instance = applicationContext.getBean(beanName);
Class<?> clazz = instance.getClass();
if(!clazz.isAnnotationPresent(GPController.class)){ continue; }
//相當於提取 class上配置的url
String baseUrl = "";
if(clazz.isAnnotationPresent(GPRequestMapping.class)){
GPRequestMapping requestMapping = clazz.getAnnotation(GPRequestMapping.class);
baseUrl = requestMapping.value();
}
//只獲取public的方法
for (Method method : clazz.getMethods()) {
if(!method.isAnnotationPresent(GPRequestMapping.class)){continue;}
//提取每個方法上面配置的url
GPRequestMapping requestMapping = method.getAnnotation(GPRequestMapping.class);
// //demo//query
String regex = ("/" + baseUrl + "/" + requestMapping.value().replaceAll("\\*",".*")).replaceAll("/+","/");
Pattern pattern = Pattern.compile(regex);
//handlerMapping.put(url,method);
handlerMappings.add(new GPHandlerMapping(pattern,instance,method));
System.out.println("Mapped : " + regex + "," + method);
}
}
}
}
3.8 一些Demo
3.8.1 MyAction(IService和Service代碼比較簡單,可自定義寫,不放代碼了)
@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){
try {
String result = modifyService.add(name, addr);
return out(response,result);
}catch (Throwable e){
Map<String,String> model = new HashMap<String,String>();
model.put("detail",e.getCause().getMessage());
model.put("stackTrace", Arrays.toString(e.getStackTrace()));
return new GPModelAndView("500",model);
}
}
@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;
}
}
3.8.2 PageAction
@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.8.3 LogAspect
@Slf4j
public class LogAspect {
//在調用一個方法之前,執行before方法
public void before(){
//這個方法中的邏輯,是由我們自己寫的
log.info("Invoker Before Method!!!");
}
//在調用一個方法之後,執行after方法
public void after(){
log.info("Invoker After Method!!!");
}
public void afterThrowing(){
log.info("出現異常");
}
}
3.8.4 resources/layouts下幾個頁面
404.html:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>頁面去火星了</title>
</head>
<body>
<font size='25' color='red'>404 Not Found</font><br/><font color='green'><i>Copyright@GupaoEDU</i></font>
</body>
</html>
500.html:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>服務器好像累了</title>
</head>
<body>
<font size='25' color='blue'>500 服務器好像有點累了,需要休息一下</font><br/>
<b>Message:¥{detail}</b><br/>
<b>StackTrace:¥{stackTrace}</b><br/>
<font color='green'><i>Copyright@GupaoEDU</i></font>
</body>
</html>
first.html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>CharlesDu SpringMVC模板引擎演示</title>
</head>
<center>
<h1>大家好,我是¥{teacher}老師<br/>歡迎大家一起來探索Spring的世界</h1>
<h3>Hello,My name is ¥{teacher}</h3>
<div>¥{data}</div>
Token值:¥{token}
</center>
</html>