大學寫的一個 Java Web庫

前言

大學剛畢業,專業是電子信息工程。大一開始學Java,準確的說是高三最後的幾周開始的. 果然興趣是最好的老師, 在大一下學期自己從前端到後臺寫了我的個人網站:TODAY BLOG 。 從註冊域名到備案再到網站成功上線,我遇到過的困難不計其數。因爲感興趣所以我堅持了下來。第一個版本使用的純Servlet寫的。後來瞭解到Java有很多開源框架可以簡化我的開發。於是又投入到新一輪的學習之中… 學了Struts2後自己學着寫了一個小框架:TODAY WEB,幾百行搞定從解析xml定義的action到處理對應的請求。學了Spring MVC後,我寫了此項目:TODAY WEB 2.0

簡介

🍎 today-web A Java library for building web applications.

安裝

<dependency>
    <groupId>cn.taketoday</groupId>
    <artifactId>today-web</artifactId>
    <version>2.3.6.RELEASE</version>
</dependency>

拉取最新代碼 => https://github.com/TAKETODAY/today-web

快速入門

第一步: 新建項目

項目結構

在這裏插入圖片描述

第二步:引入依賴

<dependency>
    <groupId>cn.taketoday</groupId>
    <artifactId>today-web</artifactId>
    <version>2.3.6.RELEASE</version>
</dependency>

<dependency>
    <groupId>cn.taketoday</groupId>
    <artifactId>today-context</artifactId>
    <version>2.1.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.28</version>
</dependency>

到此項目建立完畢,並不需要去管 web.xml 文件

第三步:配置控制器

/**
 * @author Today <br>
 *         2018-12-02 22:30
 */
@RestController
@RequestMapping("index")
public class IndexController {

    @GET("{key}")
    public String index(@PathVariable int key) {
    	return key + "";
    }
	
    @GET
    @ResponseBody(false)
    public String index() {
    	return "index";
    }
}

Freemarker模板

在這裏插入圖片描述

第四步:部署項目到Tomcat

查看效果

@GET("{key}")

https://cdn.taketoday.cn/upload/2020/1/9/pathVar.png

@GET

案例

文檔

使用說明

函數式路由

@Component
@ResponseBody
public class FunctionController {

    public String function(RequestContext request) {
        return "body:" + request.method() + " requestURI -> " + request.requestURI();
    }

    public String test(RequestContext request) {
        return "body:" + request.method() + " test -> " + request.requestURI();
    }

    public void script(RequestContext request) throws IOException {

        ModelAndView modelAndView = new ModelAndView();
        request.modelAndView(modelAndView);

        modelAndView.setContentType("text/html;charset=UTF-8");
        modelAndView.setView(new StringBuilder("<script>alert('HELLO, 你好 script');</script>"));
    }
}

@Configuration
//@EnableDefaultMybatis
//@EnableRedissonCaching
public class WebMvcConfig implements WebMvcConfiguration {

    @Autowired
    private FunctionController functionController;

    @Override
    public void configureFunctionHandler(FunctionHandlerRegistry registry) {

        registry.get("/function", functionController::function);
        registry.get("/function/test", functionController::test);
        registry.get("/function/script", functionController::script);

        registry.get("/function/error/500", (context) -> {
            context.sendError(500);
        });
    }
}

註解路由

//@Controller
@RestController
@RequestMapping("/users")
public class UserController {
    

    @GET("index")
    @POST("post")
    @PUT("articles/{id}")
    ......
    @RequestMapping("/users/{id}")
    @RequestMapping(value = "/**", method = {RequestMethod.GET})
    @RequestMapping(value = "/*.html", method = {RequestMethod.GET})
    @RequestMapping(value = {"/index.action", "/index.do", "/index"}, method = RequestMethod.GET)
    @Interceptor({LoginInterceptor.class, ...})
    public (String|List<?>|Set<?>|Map<?>|void|File|Image|...) \\w+ (request, request, session,servletContext, str, int, long , byte, short, boolean, @Session("loginUser"), @Header("User-Agent"), @Cookie("JSESSIONID"), @PathVariable("id"), @RequestBody("users"), @Multipart("uploadFiles") MultipartFile[]) {
        service...
        return </>;
    }
}

ViewController

@Configuration
public class WebMvcConfig implements WebMvcConfiguration {

    @Override
    public void configureViewController(ViewControllerHandlerRegistry registry) {
        registry.addViewController("/github", "redirect:https://github.com");
        registry.addRedirectViewController("/login.do", "/login");
        registry.addViewController("/login.action")
                .setAssetsPath("redirect:/login");
    }
}

靜態資源

@Singleton
@Profile("dev")
public ResourceHandlerRegistry devRsourceMappingRegistry(@Env("site.uploadPath") String upload,
                                                         @Env("site.assetsPath") String assetsPath) //
{
    final ResourceHandlerRegistry registry = new ResourceHandlerRegistry();

    registry.addResourceMapping("/assets/**")//
            .addLocations(assetsPath);

    registry.addResourceMapping("/upload/**")//
            .addLocations(upload);

    registry.addResourceMapping("/logo.png")//
            .addLocations("file:///D:/dev/www.yhj.com/webapps/assets/images/logo.png");

    registry.addResourceMapping("/favicon.ico")//
            .addLocations("classpath:/favicon.ico");

    return registry;
}

@Singleton
@Profile("prod")
public ResourceHandlerRegistry prodResourceMappingRegistry() {

    final ResourceHandlerRegistry registry = new ResourceHandlerRegistry();

    registry.addResourceMapping(LoginInterceptor.class)//
            .setPathPatterns("/assets/admin/**")//
            .setOrder(Ordered.HIGHEST_PRECEDENCE)//
            .addLocations("/assets/admin/");

    return registry;
}

@Override
public void configureResourceHandler(ResourceHandlerRegistry registry) {

    registry.addResourceMapping(LoginInterceptor.class)//
            .setPathPatterns("/assets/admin/**")//
            .setOrder(Ordered.HIGHEST_PRECEDENCE)//
            .addLocations("/assets/admin/");
}

自定義參數轉換器

@Component 
public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) throws ConversionException {
        ...
    }
}

也可以通過xml文件配置簡單視圖

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Web-Configuration PUBLIC 
		"-//TODAY BLOG//Web - Configuration DTD 2.0//CN"
			"https://taketoday.cn/framework/web/dtd/web-configuration-2.3.7.dtd">

<Web-Configuration>

    <controller prefix="/error/">
        <action resource="400" name="BadRequest" status="400" />
        <action resource="403" name="Forbidden" status="403" />
        <action resource="404" name="NotFound" status="404" />
        <action resource="500" name="ServerIsBusy" status="500" />
        <action resource="405" name="MethodNotAllowed" status="405" />
    </controller>

    <controller>
        <action resource="redirect:http://pipe.b3log.org/blogs/Today" name="today-blog-pipe" />
        <action resource="redirect:https://taketoday.cn" name="today" />
        <action resource="redirect:https://github.com" name="github" />
        <action resource="redirect:/login" name="login.do" />
    </controller>

    <controller class="cn.taketoday.web.demo.controller.XMLController" name="xmlController" prefix="/xml/">
        <action name="obj" method="obj" />
        <action name="test" resource="test" method="test"/>
    </controller>

</Web-Configuration>

登錄實例

@Controller
public class UserController {

/* 
    <controller prefix="/WEB-INF/view/" suffix=".ftl">
        <action resource="login" name="login" />
        <action resource="register" name="register" />
    </controller> */
    
    // @GET("login")
    @RequestMapping(value = "/login" , method = RequestMethod.GET)
    public String login() {
        return "/login/login";//支持jsp,FreeMarker,Thymeleaf,自定義視圖
    }
    
    @Logger("登錄")
    //@POST("/login")
    //@RequestMapping(value = "/login" , method = RequestMethod.POST)
    @ActionMapping(value = "/login", method = RequestMethod.POST)
    public String login(HttpSession session, RedirectModel redirectModel, @Valid User user, Errors error) {
    
        if (error.hasErrors()) {
            System.err.println(error.getAllErrors());
            redirectModel.attribute("msg", error.getAllErrors().toString());
            return "redirect:/login";
        }
    
        User login = userService.login(user);
        if (login == null) {
            redirectModel.attribute("userId", user.getUserId());
            redirectModel.attribute("msg", "登錄失敗");
            return "redirect:/login";
        }
        redirectModel.attribute("msg", "登錄成功");
        session.setAttribute(USER_INFO, login);
        return "redirect:/user/info";
    }
    
}

文件下載,支持直接返回給瀏覽器圖片

@RequestMapping(value = {"/download"}, method = RequestMethod.GET)
public File download(String path) {
    return new File(path);
}
@GET("/display")
public final BufferedImage display(HttpServletResponse response) throws IOException {
    response.setContentType("image/jpeg");
    return ImageIO.read(new File("D:/taketoday.cn/webapps/upload/logo.png"));
}

@GET("captcha")
public final BufferedImage captcha(HttpServletRequest request) throws IOException {
    BufferedImage image = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB);
    Graphics graphics = image.getGraphics();
    graphics.setColor(Color.WHITE);
    graphics.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT);
    Graphics2D graphics2d = (Graphics2D) graphics;
    drawRandomNum(graphics2d, request);
    return image;
}

文件上傳,支持多文件

@RequestMapping(value = { "/upload" }, method = RequestMethod.POST)
public final String upload(@Multipart MultipartFile uploadFile) throws IOException {

    String upload = "D:/www.yhj.com/webapps/upload/";
    String path = upload + uploadFile.getFileName();
    File file = new File(path);
    uploadFile.save(file);

    return "/upload/" + uploadFile.getFileName();
}

@POST({"/upload/multi"})
public final String multiUpload(HttpServletResponse response, @Multipart MultipartFile[] files) throws IOException {

    String upload = "D:/www.yhj.com/webapps/upload/";
    
    for (MultipartFile multipartFile : files) {
        String path = upload + multipartFile.getFileName();
        File file = new File(path);
        System.out.println(path);
        if (!multipartFile.save(file)) {
            return "<script>alert('upload error !')</script>";
            //response.getWriter().print("<script>alert('upload error !')</script>");
        }
    }
    //response.getWriter().print("<script>alert('upload success !')</script>");
    return "<script>alert('upload success !')</script>";
}

🙏 鳴謝

本項目的誕生離不開以下開源項目:

  • Freemarker: Apache Freemarker
  • Slf4j: Simple Logging Facade for Java
  • Spring: Spring Framework
  • EL: Java Unified Expression Language
  • FastJSON: A fast JSON parser/generator for Java
  • Lombok: Very spicy additions to the Java programming language
  • Today Context: A Java library for dependency injection and aspect oriented programing
  • Hibernate Validator: Hibernate Validator - Bean Validation 2.0 (JSR 380) Reference Implementation

📄 開源協議

請查看 GNU GENERAL PUBLIC LICENSE

GitHub

https://github.com/TAKETODAY/today-web
瘋狂暗示 😛

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章