springmvc及模拟springboot

外置tomcat

首先我们看spring的官网的springmvc部分。
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet
在这里插入图片描述官网推荐使用这种方式启动。那么我们也这样启动。

首先我们建立一个项目。不指定父项目。添加spring和springmvc这两个maven。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mymvc</groupId>
  <artifactId>mvctest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
	  <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context</artifactId>
	    <version>5.1.10.RELEASE</version>
	</dependency>
	
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-webmvc</artifactId>
	    <version>5.1.10.RELEASE</version>
	</dependency>
		

		
  
  </dependencies>
</project>
package com.test;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.springframework.web.WebApplicationInitializer;

public class MyWebApplicationInitializer implements WebApplicationInitializer {

	public void onStartup(ServletContext servletContext) throws ServletException {
		
		
	}
}

这样能发现会有报错。
在这里插入图片描述

这里是ServletContext找不到,所以我们需要引入servlet的包。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mymvc</groupId>
  <artifactId>mvctest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
	  <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context</artifactId>
	    <version>5.1.10.RELEASE</version>
	</dependency>
	
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-webmvc</artifactId>
	    <version>5.1.10.RELEASE</version>
	</dependency>
		
		<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
	<dependency>
	    <groupId>javax.servlet</groupId>
	    <artifactId>javax.servlet-api</artifactId>
	    <version>4.0.0</version>
	    <scope>provided</scope>
	</dependency>
		
  
  </dependencies>
</project>

引入了servlet的包就解决掉这个错误了。

把官网推荐的配置代码复制粘贴上去。

package com.test;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class MyWebApplicationInitializer implements WebApplicationInitializer {

	public void onStartup(ServletContext servletContext) throws ServletException {
        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
        ac.refresh();

        System.out.println("-----------test--------------");
        
        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
		
	}
}

使用tomcat启动流程。
在这里插入图片描述

在这里插入图片描述
这里打印出了test,说明这个已经MyWebApplicationInitializer这个类是起作用了的。

现在我们就能写一个controller了。这里为了方便,我把MyWebApplicationInitializer中的registration.addMapping改为registration.addMapping("/");。即

package com.test;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class MyWebApplicationInitializer implements WebApplicationInitializer {

	public void onStartup(ServletContext servletContext) throws ServletException {
        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
        ac.refresh();

        System.out.println("-----------test--------------");
        
        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
		
	}
}

写一个controller。

package com.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestController {
	
	@RequestMapping("/index")
	public String test() {
		System.out.println("---------controller----------");
		return "index";
	}
}

这里启动直接访问是访问不了的。因为没有加视图解析器。
首先在pom中添加tomcat模块。主要是tomcat-embed-core。

		<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-core</artifactId>
			<version>9.0.33</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<version>9.0.33</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-el -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-el</artifactId>
			<version>9.0.33</version>
		</dependency>

然后我们需要配置视图解析器。
一共有3种方式:xml,@bean方式,接口方式。xml方式就不写了,说一下另外2种方式。
视图解析器有多个:
在这里插入图片描述
我们选一个合适的使用就可以了。
@Bean方式
我们可以在@Configuration中,使用@Bean的方式去注册一个视图解析器。

package com.test;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@ComponentScan("com.test")
public class AppConfig {

	@Bean
	public InternalResourceViewResolver internalResourceViewResolver() {
		InternalResourceViewResolver internalResourceViewResolver=new InternalResourceViewResolver();
		internalResourceViewResolver.setPrefix("/");
		internalResourceViewResolver.setSuffix(".jsp");
		return internalResourceViewResolver;
	}
}

启动项目,访问http://localhost:8080/mvc/index。
在这里插入图片描述在这里插入图片描述

证明访问进来了。TestController已经生效。

使用接口的方式:

package com.test;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan("com.test")
public class AppConfig implements WebMvcConfigurer {

	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/",".jsp");
	}
	

//	@Bean
//	public InternalResourceViewResolver internalResourceViewResolver() {
//		InternalResourceViewResolver internalResourceViewResolver=new InternalResourceViewResolver();
//		internalResourceViewResolver.setPrefix("/");
//		internalResourceViewResolver.setSuffix(".jsp");
//		return internalResourceViewResolver;
//	}
}

在这里插入图片描述

由于使用的UrlBasedViewResolverRegistration的视图解析器,与InternalResourceViewResolver不一样,UrlBasedViewResolverRegistration会跳转到另外一个url,即再次访问http://localhost:8080/mvc/index,造成循环出错。而InternalResourceViewResolver直接使用的静态资源。所以UrlBasedViewResolverRegistration访问会出错,但是后台依然会打印。这里就不改错误了,知道原因即可。有兴趣的自己可以弄一下,这里贴下错误重点。

在这里插入图片描述

这里有一个问题,就是WebApplicationInitializer并没有做任何的操作,程序就自动扫描到了我们写的代码,这个是不是很神奇。
我们通过debug调试模式,发现以下调用链。
在这里插入图片描述

		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}

这里就是循环了所有的WebApplicationInitializer,而initializers是怎么得到的呢?
在这个类上我们能看到以下东西:
在这里插入图片描述

意思就是只要实现了ServletContainerInitializer这个接口,就能启动,如果在类上加了@HandlesTypes注解,这个注解中的接口的实现就会被扫描到。但是具体是怎么启动的呢?这个是需要配置的。
在这里插入图片描述这个配置文件代表的意思是:在这个配置文件上写上对应的类,就能启动这个类,而当前的@HandlesTypes是WebApplicationInitializer接口,我们又实现了WebApplicationInitializer,就能被扫面到,这样就拿到了我们自己的MyWebApplicationInitializer这个类。如果还不相信我们可以模拟一个。

首先我们也实现这个接口。

package com.test.myinit;

import java.util.Set;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

public class Myinit implements ServletContainerInitializer {

	public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
		System.out.println("--------Init-----------");
	}

}

启动程序:
在这里插入图片描述可以发现我们没有打印init,说明没有被执行到。

接下来我们把配置文件配置上,并且配置上我们的类:
在这里插入图片描述
在启动:
在这里插入图片描述这里执行了init,说明方法执行了,证明前面的说法是没有错的。目前是执行到了这个地方了的。

接下来我们再弄一个@HandlesTypes的实现类。
修改Myinit:

package com.test.myinit;

import java.util.Set;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;

@HandlesTypes(Test.class)
public class Myinit implements ServletContainerInitializer {

	public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
		System.out.println(c);
		System.out.println("--------Init-----------");
	}

}

新加接口和一个实现类:

package com.test.myinit;

public interface Test {

}

package com.test.myinit;

public class MyTest implements Test {

}

再次启动:
在这里插入图片描述

这里就看到它找到了实现类了。证明完毕。

内嵌tomcat

前面说了这么多,我们的tomcat是外部启动访问的,而像springboot这种是内嵌了一个tomcat,这种方式实现很简单。

我在这里有个问题,前面使用的是tomcat9.0.33,不知道为啥启动不了端口,后经过排查改成了8.5.42就行,所以这里我们将pom的tomcat版本改下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.mymvc</groupId>
	<artifactId>mvc</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>mvc Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>


		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.1.10.RELEASE</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.1.10.RELEASE</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>4.0.0</version>
			<scope>provided</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-core</artifactId>
			<version>8.5.42</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<version>8.5.42</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-el -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-el</artifactId>
			<version>8.5.42</version>
		</dependency>




	</dependencies>
	<build>
		<finalName>mvc</finalName>
	</build>
</project>

启动内置的tomcat,因为这里是内置的,所以如果只是启动的话,就跟前面没有任何关联,因此需要告诉tomcat你的源码在哪里。

package custom;

import java.io.File;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;

public class CustomSpringBoot {

	public static void run() {
		Tomcat tomcat = new Tomcat();
		String sourcePath = CustomSpringBoot.class.getResource("/").getPath();
		tomcat.setPort(8080);
		//告诉tomcat源码在哪里
		StandardContext ctx = (StandardContext) tomcat.addWebapp("/",new File("src/main/resources").getAbsolutePath());
		System.out.println("ctx:"+ctx);
		
        WebResourceRoot resources = new StandardRoot(ctx);
        resources.addPreResources(new DirResourceSet(resources, "/", sourcePath, "/"));
        ctx.setResources(resources);
		try {
			tomcat.start();
			tomcat.getServer().await();
		} catch (LifecycleException e) {
			e.printStackTrace();
		}
		System.out.println("started tomcat!!!");
	}

}

这里写一个自己的servlet:

package custom;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//获取当前路径
		String basepath = MyServlet.class.getResource("/").getPath();
		String requestURI = req.getRequestURI();
		String path=basepath+requestURI;
		System.out.println("basepath:"+basepath);
		System.out.println("requestURI:"+requestURI);
		
        resp.setContentType("text/html");
        resp.getWriter().write("aaa");
	}
}

修改Myinit.java

package com.test.myinit;

import java.util.Set;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.HandlesTypes;

import custom.MyServlet;

@HandlesTypes(Test.class)
public class Myinit implements ServletContainerInitializer {

	public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
		//启动tomcat,然后配置我们的Servlet
		System.out.println("--------Myinit----------");
		 ServletRegistration.Dynamic addServlet = ctx.addServlet("XQ", new MyServlet());
		 addServlet.setLoadOnStartup(1);
		 addServlet.addMapping("/");
	}

}

最后建立一个测试类:

package custom;

public class Test {
	public static void main(String[] args) {
		CustomSpringBoot.run();
	}
}

启动访问:
在这里插入图片描述在这里插入图片描述

这里说明内置的tomcat生效了。而且启动也初始化了。

最后再说一下怎么访问到资源文件的。
我们通过MyServlet.class.getResource("/").getPath()得到项目的绝对路径,通过req.getRequestURI()得到访问的路径。然后加在一起就是项目中要访问文件位置的绝对路径。这样就达到了访问的情况。

package custom;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//获取当前路径
		//class所在目录
		String basepath = MyServlet.class.getResource("/").getPath();
		//访问的uri
		String requestURI = req.getRequestURI();
		String path=basepath+requestURI;
		System.out.println("basepath:"+basepath);
		System.out.println("requestURI:"+requestURI);
		System.out.println("path:"+path);
		
		File file= new File(path);
        InputStream inputStream = new FileInputStream(file);
        byte[] bytes = new byte[2048];
        inputStream.read(bytes);

        inputStream.close();
        String str = new String(bytes);
        System.out.println(str);
        resp.setContentType("text/html");
        resp.getWriter().write(str);
	}
}

package com.test;


/**
 * 工具类
 */
import javax.servlet.http.HttpServletResponse;
import java.io.*;

public class FileUtils {

    public static final int DEFAULT_SPEED = 1024 * 1024;

    /**
     * 将读取到的字节利用写流写出去
     * @param is 读流
     * @param os 写流
     * @param speed 写出,读入速度
     * @return boolean
     */
    public static boolean writeFile(InputStream is, OutputStream os, int speed) {
        boolean success = false;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            bis = new BufferedInputStream(is);
            bos = new BufferedOutputStream(os);
            int fileSize = is.available();
            long written = 0;
            byte bytes[] = new byte[speed];
            while (written < fileSize) {
                if (written + speed > fileSize) {
                    speed = (int) (fileSize - written);
                    bytes = new byte[speed];
                }
                bis.read(bytes);
                bos.write(bytes);
                bos.flush();
                written += speed;
            }
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            bis.close();
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return success;
    }

    /**
     * @see FileUtils#writeFile(InputStream, OutputStream, int)
     * @param file 被读取的文件
     * @param os 写出流
     * @return boolean
     * @throws IOException
     */
    public static boolean writeFile(File file, OutputStream os) throws IOException {
        return writeFile(new FileInputStream(file), os, DEFAULT_SPEED);
    }

    public static String getSuffix(String path) {
        int index = path.lastIndexOf(".");
        return index != -1 ? path.substring(index) : "";
    }

    /**
     * 将文件read拷贝到write
     * @param read 被读取的文件
     * @param write 指向文件
     * @return boolean
     * @throws IOException
     */
    public static boolean copyFile(File read, File write) throws IOException {
        return writeFile(new FileInputStream(read), new FileOutputStream(write), DEFAULT_SPEED);
    }

//    public static boolean copyFile(MultipartFile read, File write) throws IOException {
//        return writeFile(read.getInputStream(), new FileOutputStream(write), DEFAULT_SPEED);
//    }

    public static void downloadFile(InputStream is, HttpServletResponse response) throws IOException {
        FileUtils.writeFile(is, response.getOutputStream(), DEFAULT_SPEED);
    }

    public static void downloadFile(File file, HttpServletResponse response) throws IOException {
        String fileName = file.getName();
        response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("GBK"), "ISO8859_1"));
        FileUtils.writeFile(file, response.getOutputStream());
    }

    public static boolean createFile(String path,String content){
        File myFilePath = new File(path);
        try {
            if (!myFilePath.exists()) {
                myFilePath.createNewFile();
            }
            FileWriter resultFile = new FileWriter(myFilePath);
            PrintWriter myFile = new PrintWriter(resultFile);
            myFile.println(content);
            myFile.close();
            resultFile.close();
            return true;
        }
        catch (Exception e) {
            System.out.println("新建文件操作出错");
            return false;
        }
    }


    public static boolean deleteFile(String path){
        File myDelFile = new File(path);
        try {
            myDelFile.delete();
            return true;
        }
        catch (Exception e) {
            System.out.println("删除文件操作出错");
            return false;
        }
    }

    public static boolean updateFileName(String filepath,String file2path){
        File toBeRenamed = new File(filepath);
        if (!toBeRenamed.exists() || toBeRenamed.isDirectory()) {

            System.out.println("File does not exist: "+filepath);
            return false;
        }
        File newFile = new File(file2path);
        if (toBeRenamed.renameTo(newFile)) {
            return true;
        } else {
            return false;

        }
    }

}




在这里插入图片描述
在这里插入图片描述
这样就访问到了静态资源。就类似于springboot的静态访问方式一样。
项目代码:
https://download.csdn.net/download/qq_37822914/12319683

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值