Discuss / Java / MVC高级开发,(ps:下载不了IDE插件练习代码,也不知道和廖老师的差距有多大)

MVC高级开发,(ps:下载不了IDE插件练习代码,也不知道和廖老师的差距有多大)

Topic source

净净一隅

#1 Created at ... [Delete] [Delete and Lock User]

MVC高级开发,完成:

1. getMaping、postMaping方法的反射,

2. json格式、form表单格式的post请求,

3. 登录、登出、管理员、会话 

(ps:看不到IDE插件练习也不知道差距有多大,写的不对的地方,麻烦留言)

1. 扫描所有Controller以获取所有标记有@GetMapping@PostMapping的方法

package com.tools;

import com.framework.GetDispatcher;
import com.framework.PostDispatcher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ScanController {
private Map<String,GetDispatcher> getMappings=new HashMap<>();
private Map<String, PostDispatcher> postMappings=new HashMap<>();
private static List<File> classFiles = new ArrayList<>();
private static String path="./servlet/target/classes/com/controller";
static{
scanClassFileInController(path);
}
public ScanController(){

}
public Map<String,GetDispatcher> getGetMappings() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
for(File file:classFiles) {
String clsName = getClassName(file);
Class cls = Class.forName(clsName);
Object instance = cls.newInstance();
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
GetDispatcher getDispatcher = new GetDispatcher();
if (!method.isAnnotationPresent(GetMapping.class)) {
continue;
}
String url = getMappingUrl(method,"get");
Class[] paramsClsList = method.getParameterTypes();
String[] parameterNames = getParameterNames(method);
getDispatcher.setInstance(instance);
getDispatcher.setMethod(method);
getDispatcher.setParameterClasses(paramsClsList);
getDispatcher.setParameterNames(parameterNames);
this.getMappings.put(url, getDispatcher);
}
}
return this.getMappings;
}

public Map<String, PostDispatcher> getPostMappings() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
for(File file:classFiles) {
String clsName = getClassName(file);
Class cls = Class.forName(clsName);
Object instance = cls.newInstance();
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
PostDispatcher postDispatcher = new PostDispatcher();
if (!method.isAnnotationPresent(PostMapping.class)) {
continue;
}
String url = getMappingUrl(method,"post");
Class[] paramsClsList = method.getParameterTypes();
postDispatcher.setInstance(instance);
postDispatcher.setMethod(method);
postDispatcher.setParameterClasses(paramsClsList);
this.postMappings.put(url, postDispatcher);
}
}
return this.postMappings;
}

/**
* 在path路径下扫描.class文件
* @param path
*/
public static void scanClassFileInController(String path){
FileStructor fs=new FileStructor(new File(path));
ClassFileVisistor classVisistor=new ClassFileVisistor(classFiles);
fs.handle(classVisistor);
}

/**
* 获取get请求、post请求的mapping url
* @param method
* @param findType
* @return
*/
public String getMappingUrl(Method method,String findType){
if("get".equals(findType)){
if(method.isAnnotationPresent(GetMapping.class)) {
GetMapping getMapping = method.getAnnotation(GetMapping.class);
return getMapping.value()[0];
}
}

if("post".equals(findType)){
if(method.isAnnotationPresent(PostMapping.class)) {
PostMapping postMapping = method.getAnnotation(PostMapping.class);
return postMapping.value()[0];
}
}
return null;
}

/**
* 获取class的完整类名
* @param clsFile
* @return
*/
public String getClassName(File clsFile){
String classFileName=clsFile.getName();
classFileName=classFileName.substring(0,classFileName.lastIndexOf("."));
String clsName="com.controller."+classFileName;
return clsName;
}

/**
* 获取get方法的参数名
* @param method
* @return
*/
public String[] getParameterNames(Method method){
Parameter[] parameterNames=method.getParameters();
String[] parameterList=new String[parameterNames.length];
//List<String> parameterList=new ArrayList<>();
for(int i=0;i<parameterNames.length;i++){
parameterList[i]=parameterNames[i].getName();
}
return parameterList;
}
}

2. PostDispatcher 

package com.framework;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class PostDispatcher {
Object instance; // Controller实例
Method method; // Controller方法
Class<?>[] parameterClasses; // 方法参数类型
ObjectMapper objectMapper=new ObjectMapper(); // JSON映射
public ModelAndView invoke(HttpServletRequest request, HttpServletResponse response) throws IOException, InvocationTargetException, IllegalAccessException {
Object[] arguments = new Object[parameterClasses.length];
for (int i = 0; i < parameterClasses.length; i++) {
Class<?> parameterClass = parameterClasses[i];
if (parameterClass == HttpServletRequest.class) {
arguments[i] = request;
} else if (parameterClass == HttpServletResponse.class) {
arguments[i] = response;
} else if (parameterClass == HttpSession.class) {
arguments[i] = request.getSession();
} else {
BufferedReader reader = null;
if(request.getContentType().equals("application/x-www-form-urlencoded")){
// 读取form格式的入参,并转换为json格式
String jsonData=this.formData2JsonData(request);
reader = new BufferedReader(new StringReader(jsonData));
}else{
// 读取JSON格式的入参
reader=request.getReader();
}
arguments[i] = this.objectMapper.readValue(reader, parameterClass);
}
}
return (ModelAndView) this.method.invoke(instance, arguments);
}
//读取form格式的入参,并转换为json格式的字符串
public String formData2JsonData(HttpServletRequest req){
Enumeration<String> parameters=req.getParameterNames();
Map<String,Object> map=new HashMap<>();
while(parameters.hasMoreElements()){
String key=parameters.nextElement();
Object value=req.getParameter(key);
map.put(key,value);
}
String jsonMap= JSON.toJSONString(map);
return jsonMap;
}

public void setMethod(Method method) {
this.method = method;
}

public void setParameterClasses(Class<?>[] parameterClasses) {
this.parameterClasses = parameterClasses;
}

public void setInstance(Object instance) {
this.instance = instance;
}

public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

@Override
public String toString() {
return "PostDispatcher{" +
"instance=" + instance +
", method=" + method +
", parameterClasses=" + Arrays.toString(parameterClasses) +
", objectMapper=" + objectMapper +
'}';
}
}

3. GetDispatcher 

package com.framework;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class GetDispatcher {
Object instance;
Method method;
String[] parameterNames;
Class<?>[] parameterClasses;

public ModelAndView invoke(HttpServletRequest request, HttpServletResponse response) throws InvocationTargetException, IllegalAccessException {
Object[] arguments = new Object[parameterClasses.length];
for (int i = 0; i < parameterClasses.length; i++) {
String parameterName = parameterNames[i];
Class<?> parameterClass = parameterClasses[i];
if (parameterClass == HttpServletRequest.class) {
arguments[i] = request;
} else if (parameterClass == HttpServletResponse.class) {
arguments[i] = response;
} else if (parameterClass == HttpSession.class) {
arguments[i] = request.getSession();
} else if (parameterClass == int.class) {
arguments[i] = Integer.valueOf(getOrDefault(request, parameterName, "0"));
} else if (parameterClass == long.class) {
arguments[i] = Long.valueOf(getOrDefault(request, parameterName, "0"));
} else if (parameterClass == boolean.class) {
arguments[i] = Boolean.valueOf(getOrDefault(request, parameterName, "false"));
} else if (parameterClass == String.class) {
arguments[i] = getOrDefault(request, parameterName, "");
} else {
throw new RuntimeException("Missing handler for type: " + parameterClass);
}
}
return (ModelAndView) this.method.invoke(this.instance, arguments);
}

private String getOrDefault(HttpServletRequest request, String name, String defaultValue) {
String s = request.getParameter(name);
return s == null ? defaultValue : s;
}

public void setInstance(Object instance) {
this.instance = instance;
}

public Object getInstance() {
return instance;
}

public Class<?>[] getParameterClasses() {
return parameterClasses;
}

public void setParameterClasses(Class<?>[] parameterClasses) {
this.parameterClasses = parameterClasses;
}

public Method getMethod() {
return method;
}

public void setMethod(Method method) {
this.method = method;
}

public String[] getParameterNames() {
return parameterNames;
}

public void setParameterNames(String[] parameterNames) {
this.parameterNames = parameterNames;
}

@Override
public String toString() {
return "GetDispatcher{" +
"instance=" + instance +
", method=" + method +
", parameterNames=" + Arrays.toString(parameterNames) +
", parameterClasses=" + Arrays.toString(parameterClasses) +
'}';
}
}

4. ViewEngine 

package com.framework;
import com.mitchellbosecke.pebble.PebbleEngine;
import com.mitchellbosecke.pebble.loader.ServletLoader;
import com.mitchellbosecke.pebble.template.PebbleTemplate;

import javax.servlet.ServletContext;
import java.io.IOException;
import java.io.Writer;

public class ViewEngine {
private final PebbleEngine engine;
public ViewEngine(ServletContext servletContext) {
// 定义一个ServletLoader用于加载模板:
ServletLoader loader = new ServletLoader(servletContext);
// 模板编码:
loader.setCharset("UTF-8");
// 模板前缀,这里默认模板必须放在`/WEB-INF/templates`目录:
loader.setPrefix("/WEB-INF/templates");
// 模板后缀:
loader.setSuffix("");
// 创建Pebble实例:
this.engine = new PebbleEngine.Builder()
.autoEscaping(true) // 默认打开HTML字符转义,防止XSS攻击
.cacheActive(false) // 禁用缓存使得每次修改模板可以立刻看到效果
.loader(loader).build();
}

public void render(ModelAndView mv, Writer writer) throws IOException {
// 查找模板:
PebbleTemplate template = this.engine.getTemplate(mv.view);
// 渲染:
template.evaluate(writer, mv.model);
}
}

5. DispatcherServlet 

package com.framework
import com.tools.ScanController;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

@WebServlet(urlPatterns = "/")
public class DispatcherServlet extends HttpServlet {
private Map<String,GetDispatcher> getMappings=new HashMap<>();
private Map<String, PostDispatcher> postMappings = new HashMap<>();
private ViewEngine viewEngine;
@Override
public void init() throws ServletException {
System.out.println("扫描post、get请求开始");
this.getMappings = scanGetInControllers();
this.postMappings = scanPostInControllers();
this.viewEngine = new ViewEngine(this.getServletContext());
System.out.println("扫描post、get请求结束");
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
String path = req.getRequestURI().substring(req.getContextPath().length());
// 根据路径查找GetDispatcher:
GetDispatcher dispatcher = this.getMappings.get(path);
if (dispatcher == null) {
// 未找到返回404:
resp.sendError(404);
return;
}
// 调用Controller方法获得返回值:
ModelAndView mv = null;
try {
mv = dispatcher.invoke(req, resp);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// 允许返回null:
if (mv == null) {
return;
}
// 允许返回`redirect:`开头的view表示重定向:
if (mv.view.startsWith("redirect:")) {
resp.sendRedirect(mv.view.substring(9));
return;
}
// 将模板引擎渲染的内容写入响应:
PrintWriter pw = resp.getWriter();
this.viewEngine.render(mv, pw);
pw.flush();
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
String path = req.getRequestURI().substring(req.getContextPath().length());
// 根据路径查找GetDispatcher:
PostDispatcher dispatcher = this.postMappings.get(path);
if (dispatcher == null) {
// 未找到返回404:
resp.sendError(404);
return;
}
// 调用Controller方法获得返回值:
ModelAndView mv = null;
try {
mv = dispatcher.invoke(req, resp);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// 允许返回null:
if (mv == null) {
return;
}
// 允许返回`redirect:`开头的view表示重定向:
if (mv.view.startsWith("redirect:")) {
resp.sendRedirect(mv.view.substring(9));
return;
}
// 将模板引擎渲染的内容写入响应:
PrintWriter pw = resp.getWriter();
this.viewEngine.render(mv, pw);
pw.flush();
}

private Map<String,GetDispatcher> scanGetInControllers(){
ScanController scan=new ScanController();
try {
return scan.getGetMappings();
}catch (ClassNotFoundException e){
return null;
} catch (InstantiationException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}

private Map<String, PostDispatcher> scanPostInControllers() {
ScanController scan=new ScanController();
try {
return scan.getPostMappings();
}catch (ClassNotFoundException e){
return null;
} catch (InstantiationException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}

}

净净一隅

#2 Created at ... [Delete] [Delete and Lock User]

6. user\school等javabean的定义

package com.entity;

public class User {
private long id;
private String name;
private School school;
private Boolean isManager=false;

public User(long id,String name,School school){
this.id=id;
this.name=name;
this.school=school;
}

public User(String name,School school, Boolean isManager){
this.name=name;
this.school=school;
this.isManager=isManager;
}

public User(){
}

public School getSchool() {
return school;
}

public String getName() {
return name;
}

public Boolean isManager(){
return this.isManager;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", school=" + school +
", isManager=" + isManager +
'}';
}
}

package com.entity;

public class School {
public String name;
public String address;

public School(String name,String address){
this.name=name;
this.address=address;
}

public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setAddress(String address) {
this.address = address;
}

public String getAddress() {
return address;
}

@Override
public String toString() {
return "School{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}

package com.entity;

public class SignIn {
private String username;
private String password;

public String getUsername() {
return username;
}

public void setName(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public String toString() {
return "SignIn{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}

package com.entity;

public class UserProfile {
private String url;
private String username;
public UserProfile(){

}

public UserProfile(String username,String url){
this.url=url;
this.username=username;
}

public String getUrl() {
return url;
}

public String getUsername() {
return username;
}
}

净净一隅

#3 Created at ... [Delete] [Delete and Lock User]

7  templates下的html

index.html

<!DOCTYPE html\>

<html lang\="en"\> <head> <meta charset\="UTF-8"\> <title>首页</title> </head> <body> {% set name = user.getName %} <h2>Welcome,{{name!=null?name:"Guest"}} </h2> <p> {% if name==null %} <a href\="/signin"\>Sign in</a>\> {% else %} <a href\="/signout"\>Sign out</a>\> {% endif %} </p> </body> </html>

profile.html

<html> <body> <ul> {% for user in users %} <li><a href\="{{ user.getUrl }}"\>{{ user.getUsername }}</a></li> {% endfor %} </ul> </body> </html>

signin.html

<!DOCTYPE html\>

<html lang="en">

<head> <meta charset\="UTF-8"\> <title>sign in</title> </head> <body> <h1>sign in!</h1> <form action\=/signin method\=post\> <p>Username: <input name\="username"\></p> <p>Password: <input name\="password" type\="password"\></p> <p><button type\="submit"\>Sign In</button> <a href\="/"\>Cancel</a></p> </form> </body> </html>

净净一隅

#4 Created at ... [Delete] [Delete and Lock User]

8.  user controller

package com.controller;
import com.entity.School;
import com.entity.SignIn;
import com.entity.UserProfile;
import com.framework.ModelAndView;
import com.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UserController {
// 模拟一个数据库:
private Map<String, String> users = Map.of("bob", "bob123", "alice", "alice123", "tom", "tomcat");

@GetMapping("/signin")
public ModelAndView signin() {
ModelAndView mv=new ModelAndView("/signin.html");
return mv;
}

@PostMapping("/signin")
public ModelAndView doSignin(HttpServletRequest req,SignIn loginInfo) {
String expectPwd=users.get(loginInfo.getUsername());
if(!expectPwd.equals(loginInfo.getPassword())){
return null;
}
School school=new School("hua xi hospital","cd");
User user=new User(loginInfo.getUsername(),school,true);
req.getSession().setAttribute("user", user);
req.getSession().setMaxInactiveInterval(1000);
Map<String,Object> model=new HashMap<>();
model.put("user",user);
return new ModelAndView("/index.html",model);
}

@GetMapping("/signout")
public ModelAndView signout(HttpSession session) {
session.removeAttribute("user");
ModelAndView mv=new ModelAndView("/index.html");
return mv;
}

@GetMapping("/user/profile")
public ModelAndView profile(HttpServletResponse response, HttpSession session) throws IOException {
User user = (User) session.getAttribute("user");
if (user == null) {
// 未登录,跳转到登录页:
return new ModelAndView("redirect:/signin");
}
if (!user.isManager()) {
// 权限不够,返回403:
response.sendError(403);
return null;
}
List<UserProfile> usersList=new ArrayList<>();
for(String key:this.users.keySet()){
UserProfile userProfile=new UserProfile(key,key+"_url");
usersList.add(userProfile);
}
return new ModelAndView("/profile.html", Map.of("users", usersList));
}
}

净净一隅

#5 Created at ... [Delete] [Delete and Lock User]

9. index controller

package com.controller;
import com.entity.User;
import com.framework.ModelAndView;
import org.springframework.web.bind.annotation.GetMapping;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

public class IndexController {
@GetMapping("/index")
public ModelAndView index(HttpSession session) {
User user=(User)session.getAttribute("user");
Map<String,Object> model=new HashMap<>();
model.put("user",user);
ModelAndView mv=new ModelAndView("/index.html",model);
return mv;
}
}

Loading...

#6 Created at ... [Delete] [Delete and Lock User]

这种又臭又长的代码不要提上来,,,

🌙

#7 Created at ... [Delete] [Delete and Lock User]

这种最后上传git 给个链接 ,别人有兴趣获取会拉下来 看看

这种 估计 自己 都不会再看第二遍了 

还指望别人 给你看。。。

🌙

#8 Created at ... [Delete] [Delete and Lock User]

最好。。。。顺便打个广告

java: java 代码练习 (gitee.com)

这个网站的练习代码,就是没有廖大那么清晰,不过,后面会优化一下

自己仓库也有其他的一些学习项目


  • 1

Reply