Day47
Day47
手写Spring-MVC之DispatcherServlet
DispatcherServlet的思路:
前端传来URI,在TypeContainer容器类中通过uri得到对应的类描述类对象(注意:在监听器封装类描述类对象的时候,是针对于每一个URI进行封装的,也就是说每一个方法(uri)都有一个类描述类),通过类描述类对象获得类对象和方法描述类对象,再通过方法描述类对象获得方法对象和参数描述类对象。对参数描述类对象进行处理获得参数数组,然后通过method.invoke()执行方法,并返回值,最后处理返回值。
public class DispatherServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charSet=UTF-8");String uri = request.getRequestURI();HashMap<String, BeanDefinition> maps = TypeContainer.getMaps();BeanDefinition beanDefinition = maps.get(uri);if(beanDefinition==null){//System.out.println("没找到该uri下的类描述类");throw new FrameWorkException(ResponseCode.REQUEST_PATH_EXCEPTION.getCode(),ResponseCode.REQUEST_PATH_EXCEPTION.getMessage());}Object t = beanDefinition.getT();MethodDefinition methodDefinition = beanDefinition.getMethodDefinition();Method method = methodDefinition.getMethod();method.setAccessible(true);Model model = new Model();List<ParameterDefinition> parameterDefinitions = methodDefinition.getParameterDefinitions();Object[] args = handlerParameterArgs(parameterDefinitions, request, response,model);try{//调用Controller层里的某个方法Object returnVal = method.invoke(t, args);if(returnVal!=null){//处理返回值handlerReturnVal(methodDefinition,returnVal,request,response,model);}}catch (Exception e){System.out.println("出现异常了,处理全局异常");}}public void handlerReturnVal(MethodDefinition methodDefinition,Object returnVal,HttpServletRequest request,HttpServletResponse response,Model model) throws ServletException, IOException {if(methodDefinition.isResponseBodyHasOrNot()){//返回数据为JSON格式String jsonString = JSON.toJSONString(returnVal);sendResponse(response,jsonString);}else if(returnVal.getClass()==String.class){//如果返回值是字符串,先添加请求数据,再跳转(转发)handlerRequestVal(request,model.getMaps());jumpPage(returnVal,request,response);} else if (returnVal.getClass() == ModelAndView.class) {//如果返回值是ModelAndView,添加请求后跳转(转发)ModelAndView modelAndView = (ModelAndView) returnVal;handlerRequestVal(request,modelAndView.getMaps());jumpPage(modelAndView.getViewName(),request,response);}}public void sendResponse(HttpServletResponse response,String jsonString) throws IOException {response.getWriter().write(jsonString);}public void handlerRequestVal(HttpServletRequest request,Map<String,Object> maps){Set<Map.Entry<String, Object>> entries = maps.entrySet();for (Map.Entry<String, Object> entry : entries) {String key = entry.getKey();Object value = entry.getValue();request.setAttribute(key,value);}}public void jumpPage(Object returnVal,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {String str = (String) returnVal;request.getRequestDispatcher(str).forward(request,response);}public Object[] handlerParameterArgs(List<ParameterDefinition> parameterDefinitions,HttpServletRequest request,HttpServletResponse response,Model model){if(parameterDefinitions==null){return null;}Object[] args = new Object[parameterDefinitions.size()];for (ParameterDefinition parameterDefinition : parameterDefinitions) {Class<?> clazz = parameterDefinition.getClazz();//获取参数的class对象String name = parameterDefinition.getName();//获取参数的名字int index = parameterDefinition.getIndex();//获取参数的下标if(judgeTypeIsJavaOrNot(clazz)){//判断是否是Java常用数据类型args = handlerJavaType(request, name, clazz, args, index);} else if (clazz==HttpServletRequest.class) {//判断是否是请求类型args[index] = request;} else if (clazz==HttpServletResponse.class) {//判断是否是响应类型args[index] = response;} else if (clazz == String[].class) {//判断是否是数组类型String[] arr = request.getParameterValues(name);args[index] = arr;} else if (clazz == List.class) {//判断是否是List集合类型handlerListType(request,parameterDefinition,args,index);} else if (clazz== Model.class) {//判断是否是Model类型args[index] = model;}else{//判断是否是自定义类型handlerOtherType(parameterDefinition,request,args,index);}}return args;}public void handlerOtherType(ParameterDefinition parameterDefinition,HttpServletRequest request,Object[] args,int index){try {if(parameterDefinition.isRequestBodyHasOrNot()){//如果返回的是JSON格式数据BufferedReader br = request.getReader();StringBuffer sb = new StringBuffer();char[] cs = new char[1024];int len;while((len= br.read(cs))!=-1){sb.append(cs,0,len);}String jsonStr = sb.toString();Object obj = JSON.parseObject(jsonStr,parameterDefinition.getClazz());args[index] = obj;}else{Object obj = parameterDefinition.getClazz().newInstance();Map<String, String[]> parameterMap = request.getParameterMap();BeanUtils.populate(obj,parameterMap);args[index] = obj;}} catch (InstantiationException | IllegalAccessException | InvocationTargetException | IOException e) {throw new RuntimeException(e);}}public void handlerListType(HttpServletRequest request,ParameterDefinition parameterDefinition,Object[] args,int index){Map<String, String[]> parameterMap = request.getParameterMap();//key --- Value//user[0].username --- new String[]{"pengyuyan"};//user[0].password --- new String[]{"123123"};//user[1].username --- new String[]{"wuyanzu"};//user[1].password --- new String[]{"123456"};//获取泛型类型Type pt = parameterDefinition.getActualTypeArguments()[0];String className = pt.getTypeName();Class<?> aClass = null;try {aClass = Class.forName(className);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}ArrayList<Object> list = new ArrayList<>();Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();for (Map.Entry<String, String[]> entry : entries) {String key = entry.getKey();//user[0].usernameString[] value = entry.getValue();//new String[]{"guodan"}int i = Integer.parseInt(key.substring(key.indexOf("[") + 1, key.indexOf("]")));//集合中的下标String fieldName = key.substring(key.indexOf(".") + 1);//集合中元素对象的属性名String fieldValue = value[0];//获取集合中元素对象里的属性值Object o =null;try{o = list.get(i);}catch (IndexOutOfBoundsException e){//该集合下标上没有元素try {o = aClass.newInstance();//创建对象list.add(o);//添加对象} catch (InstantiationException | IllegalAccessException ex) {throw new RuntimeException(ex);}}try {BeanUtils.setProperty(o,fieldName,fieldValue);//设置对象属性} catch (IllegalAccessException | InvocationTargetException ex) {throw new RuntimeException(ex);}args[index] = list;}}public Object[] handlerJavaType(HttpServletRequest request,String name,Class<?> clazz,Object[] args,int index){String parameter = request.getParameter(name);if(clazz==byte.class || clazz==Byte.class){args[index] = Byte.parseByte(parameter);}else if(clazz==short.class || clazz==Short.class){args[index] = Short.parseShort(parameter);}else if(clazz==int.class || clazz==Integer.class){args[index] = Integer.parseInt(parameter);}else if(clazz==long.class || clazz==Long.class){args[index] = Long.parseLong(parameter);}else if(clazz==float.class || clazz==Float.class){args[index] = Float.parseFloat(parameter);}else if(clazz==double.class || clazz==Double.class){args[index] = Double.parseDouble(parameter);}else if(clazz==char.class || clazz==Character.class){args[index] = parameter.toCharArray()[0];}else if(clazz==boolean.class || clazz==Boolean.class){args[index] = Boolean.parseBoolean(parameter);}if(clazz==String.class){args[index] = parameter;}return args;}public boolean judgeTypeIsJavaOrNot(Class<?> clazz){if(clazz==byte.class || clazz==Byte.class || clazz==short.class || clazz==Short.class || clazz==int.class || clazz== Integer.class || clazz==long.class || clazz== Long.class || clazz==float.class || clazz== Float.class || clazz==double.class || clazz==Double.class || clazz==char.class || clazz== Character.class || clazz==boolean.class || clazz==Boolean.class || clazz==String.class){return true;}return false;}}
其中的细节和难点:
1.处理参数
处理参数的思路:
获取参数的class对象、参数的名字、参数的下标。然后根据参数名利用请求从前端获取对应的参数对象并添加到参数数组args[]中,位置为对应下标的位置。
其中需要根据不同的参数类型分别进行处理:
如果是Java常用数据类型(8大基本数据类型+string),则进行装箱处理(String 直接添加),然后添加到参数数组args[]中;
public Object[] handlerJavaType(HttpServletRequest request,String name,Class<?> clazz,Object[] args,int index){String parameter = request.getParameter(name);if(clazz==byte.class || clazz==Byte.class){args[index] = Byte.parseByte(parameter);}else if(clazz==short.class || clazz==Short.class){args[index] = Short.parseShort(parameter);}else if(clazz==int.class || clazz==Integer.class){args[index] = Integer.parseInt(parameter);}else if(clazz==long.class || clazz==Long.class){args[index] = Long.parseLong(parameter);}else if(clazz==float.class || clazz==Float.class){args[index] = Float.parseFloat(parameter);}else if(clazz==double.class || clazz==Double.class){args[index] = Double.parseDouble(parameter);}else if(clazz==char.class || clazz==Character.class){args[index] = parameter.toCharArray()[0];}else if(clazz==boolean.class || clazz==Boolean.class){args[index] = Boolean.parseBoolean(parameter);}if(clazz==String.class){args[index] = parameter;}return args;}public boolean judgeTypeIsJavaOrNot(Class<?> clazz){if(clazz==byte.class || clazz==Byte.class || clazz==short.class || clazz==Short.class || clazz==int.class || clazz== Integer.class || clazz==long.class || clazz== Long.class || clazz==float.class || clazz== Float.class || clazz==double.class || clazz==Double.class || clazz==char.class || clazz== Character.class || clazz==boolean.class || clazz==Boolean.class || clazz==String.class){return true;}return false;}
如果是请求/响应类型的数据则直接添加到数组中;
如果是数组,则获取的是数组对象,并添加到args[]中;
String[] arr = request.getParameterValues(name); args[index] = arr;
如果是List集合类型(前端设计页面的时候会规范返回的格式),则要先通过获取泛型(这里需要回到参数描述类中添加泛型类型这一属性)来获取集合里面元素的类型,然后获得传入的数据map,遍历每行数据拼接出元素的名字、下标和属性值。然后通过元素的类型利用反射创建类对象,创建List集合并添加对象,设置对象属性值(注意:这里有一个小技巧,利用try-catch先获取空集合里面的元素,在出现没有元素的异常后在catch中创建对象,并添加到list中。这样在同一个元素下标中的list位置就有了对象,就不会进入到异常处理中创建对象,而是在后续进行属性设置,直到下标改变再重新创建对象。),最后将List集合添加到args[]中;
参数类型描述类添加泛型属性(相应的需要修改监听器封装部分的代码):
@NoArgsConstructor @AllArgsConstructor @Data public class ParameterDefinition {private String name;//参数名private Class<?> clazz;//参数类型private int index;//参数下标private Type[] actualTypeArguments;//参数泛型的数组}
监听器相关部分:
if(parameters.length!=0){for (int i = 0; i < parameters.length; i++) {//获取参数上泛型数组Type parameterizedType = parameters[i].getParameterizedType();Type[] actualTypeArguments = null;try{ParameterizedType pt = (ParameterizedType) parameterizedType;if(pt!=null){actualTypeArguments = pt.getActualTypeArguments();}}catch (Exception e){}String parameterName = parameters[i].getName();//获取参数名Class<?> parameterType = parameters[i].getType();//参数类型int index = i;//下标ParameterDefinition parameterDefinition = new ParameterDefinition(parameterName, parameterType, index,actualTypeArguments);//封装参数描述类对象parameterList.add(parameterDefinition);} }
DispatcherServlet:
public void handlerListType(HttpServletRequest request,ParameterDefinition parameterDefinition,Object[] args,int index){Map<String, String[]> parameterMap = request.getParameterMap();//key --- Value//user[0].username --- new String[]{"pengyuyan"};//user[0].password --- new String[]{"123123"};//user[1].username --- new String[]{"wuyanzu"};//user[1].password --- new String[]{"123456"};//获取泛型类型Type pt = parameterDefinition.getActualTypeArguments()[0];String className = pt.getTypeName();Class<?> aClass = null;try {aClass = Class.forName(className);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}ArrayList<Object> list = new ArrayList<>();Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();for (Map.Entry<String, String[]> entry : entries) {String key = entry.getKey();//user[0].usernameString[] value = entry.getValue();//new String[]{"guodan"}int i = Integer.parseInt(key.substring(key.indexOf("[") + 1, key.indexOf("]")));//集合中的下标String fieldName = key.substring(key.indexOf(".") + 1);//集合中元素对象的属性名String fieldValue = value[0];//获取集合中元素对象里的属性值Object o =null;try{o = list.get(i);}catch (IndexOutOfBoundsException e){//该集合下标上没有元素try {o = aClass.newInstance();//创建对象list.add(o);//添加对象} catch (InstantiationException | IllegalAccessException ex) {throw new RuntimeException(ex);}try {BeanUtils.setProperty(o,fieldName,fieldValue);//设置对象属性} catch (IllegalAccessException | InvocationTargetException ex) {throw new RuntimeException(ex);}args[index] = list;}}}
如果是Model类型(model需要创建,属性只有一个map,用来存放属性的名和值,同时有一个setAttribute()方法,即添加键值。model是用来跳转页面的,将前端的数据封装到自己的容器属性中,然后通过请求传递给前端。同时创建一个ModelAndView类,除了容器属性外还有一个字符串类型的路径,功能和model类似,但适用于需要动态指定跳转页面的复杂业务),则直接添加到args[]中;
public class Model {private Map<String,Object> maps= new ConcurrentHashMap<>();public void setAttributes(String key,Object value){maps.put(key,value);}public Map<String, Object> getMaps() {return maps;} }public class ModelAndView {private Map<String,Object> maps = new HashMap<>();private String viewName;public void setAttributes(String key,Object value){maps.put(key,value);}public Map<String, Object> getMaps() {return maps;}public void setMaps(Map<String, Object> maps) {this.maps = maps;}public String getViewName() {return viewName;}public void setViewName(String viewName) {this.viewName = viewName;} }
如果是自定义类型,则用反射创建对象,将数据利用BeanUtils工具类的populate方法将参数整合到类对象中,并添加到args[]中。
public void handlerOtherType(Class<?> clazz,HttpServletRequest request,Object[] args,int index){try {Object obj = clazz.newInstance();Map<String, String[]> parameterMap = request.getParameterMap();BeanUtils.populate(obj,parameterMap);args[index] = obj;} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);}}
2.处理返回值
思路:
如果返回值不为空,即该方法有返回值,则要对返回值的类型进行判断,然后添加请求数据,再进行转发。
不同类型返回值的处理:
这里返回值有两种情况,本质是跳转逻辑的不同。一种是字符串类型的路径,controller层会将前端的数据封装到Model对象中,servlet就获取model的map属性,遍历里面的数据利用请求设置到页面,而返回的字符串路径直接用来跳转,一种是ModelAndView类型的对象,同样遍历map属性,将属性通过请求设置到页面,并利用类里面的路径属性进行跳转。
public void handlerReturnVal(Object returnVal,HttpServletRequest request,HttpServletResponse response,Model model) throws ServletException, IOException {if(returnVal.getClass()==String.class){//如果返回值是字符串,先添加请求数据,再跳转(转发)handlerRequestVal(request,model.getMaps());jumpPage(returnVal,request,response);} else if (returnVal.getClass() == ModelAndView.class) {//如果返回值是ModelAndView,添加请求后跳转(转发)ModelAndView modelAndView = (ModelAndView) returnVal;handlerRequestVal(request,modelAndView.getMaps());jumpPage(modelAndView.getViewName(),request,response);}}//遍历Model/ModelAndView类对象的容器属性,把属性数据添加到请求public void handlerRequestVal(HttpServletRequest request,Map<String,Object> maps){Set<Map.Entry<String, Object>> entries = maps.entrySet();for (Map.Entry<String, Object> entry : entries) {String key = entry.getKey();Object value = entry.getValue();request.setAttribute(key,value);}}//页面跳转public void jumpPage(Object returnVal,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {String str = (String) returnVal;request.getRequestDispatcher(str).forward(request,response);}
3.处理JSON数据
如果接收的是JSON格式数据,那么如何识别数据以及怎样传递数据呢?
**思路:**参数注解用来识别判断客户端传递过来的数据是否是JSON数据,需要将JSON格式的字符串解析成参数类型的数据;方法注解表示服务器传输过去的数据为JSON数据,需要将返回值解析成JSON格式的字符串。
具体实现:添加RequestBody注解用在参数上,和ResponseBody注解用在方法上。
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface RequestBody { }@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ResponseBody { }
DispatcherServlet中在创建参数数组的时候判断参数上是否有注解,所以要在参数描述类中添加用来判断是否参数有注解的布尔值。在方法描述类中添加布尔值判断方法上是否有注解。(相应的要修改监听器中封装类的那部分代码)
参数描述类和方法描述类修改:
@NoArgsConstructor @AllArgsConstructor @Data public class ParameterDefinition {private String name;//参数名private Class<?> clazz;//参数类型private int index;//参数下标private Type[] actualTypeArguments;//参数泛型的数组private boolean requestBodyHasOrNot;//参数上是否有@RequestBody注解}@NoArgsConstructor @AllArgsConstructor @Data public class MethodDefinition {private String requestMappingPath;//子级URiprivate String name;//方法名private Method method;//方法对象private Class<?> returnClazz;//返回值类型private List<ParameterDefinition> parameterDefinitions;//参数描述类对象的集合private boolean responseBodyHasOrNot;//方法上是否有@ResponseBody注解 }
监听器相关部分:
if(parameters.length!=0){for (int i = 0; i < parameters.length; i++) {//获取参数上泛型数组Type parameterizedType = parameters[i].getParameterizedType();Type[] actualTypeArguments = null;try{ParameterizedType pt = (ParameterizedType) parameterizedType;if(pt!=null){actualTypeArguments = pt.getActualTypeArguments();}}catch (Exception e){}String parameterName = parameters[i].getName();//获取参数名Class<?> parameterType = parameters[i].getType();//参数类型int index = i;//下标//获取参数上是否有@RequestBody注解boolean requestBodyHasOrNot = false;RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);if(requestBody!=null){requestBodyHasOrNot = true;}ParameterDefinition parameterDefinition = new ParameterDefinition(parameterName, parameterType, index,actualTypeArguments,requestBodyHasOrNot);//封装参数描述类对象parameterList.add(parameterDefinition);} }//获取方法上是否有@ResponseBody注解 boolean responseBodyHasOrNot = false; ResponseBody responseBody = method.getAnnotation(ResponseBody.class); if(responseBody!=null){responseBodyHasOrNot = true; } MethodDefinition methodDefinition = new MethodDefinition(sonUri, methodName, method, returnType, parameterList,responseBodyHasOrNot);//封装方法描述类对象
servlet中在自定义类型中要判断是否有对应的注解,如果有就解析json数据封装成对象然后添加到数组。
public void handlerOtherType(ParameterDefinition parameterDefinition,HttpServletRequest request,Object[] args,int index){try {if(parameterDefinition.isRequestBodyHasOrNot()){//如果返回的是JSON格式数据BufferedReader br = request.getReader();StringBuffer sb = new StringBuffer();char[] cs = new char[1024];int len;while((len= br.read(cs))!=-1){sb.append(cs,0,len);}String jsonStr = sb.toString();Object obj = JSON.parseObject(jsonStr,parameterDefinition.getClazz());args[index] = obj;}else{Object obj = parameterDefinition.getClazz().newInstance();Map<String, String[]> parameterMap = request.getParameterMap();BeanUtils.populate(obj,parameterMap);args[index] = obj;}} catch (InstantiationException | IllegalAccessException | InvocationTargetException | IOException e) {throw new RuntimeException(e);} }
在方法处理中判断是否有对应的方法注解,如果有就将返回的JSON转换为字符串写回前端。
public void handlerReturnVal(MethodDefinition methodDefinition,Object returnVal,HttpServletRequest request,HttpServletResponse response,Model model) throws ServletException, IOException {if(methodDefinition.isResponseBodyHasOrNot()){//返回数据为JSON格式String jsonString = JSON.toJSONString(returnVal);sendResponse(response,jsonString);}else if(returnVal.getClass()==String.class){//如果返回值是字符串,先添加请求数据,再跳转(转发)handlerRequestVal(request,model.getMaps());jumpPage(returnVal,request,response);} else if (returnVal.getClass() == ModelAndView.class) {//如果返回值是ModelAndView,添加请求后跳转(转发)ModelAndView modelAndView = (ModelAndView) returnVal;handlerRequestVal(request,modelAndView.getMaps());jumpPage(modelAndView.getViewName(),request,response);}}public void sendResponse(HttpServletResponse response,String jsonString) throws IOException {response.getWriter().write(jsonString);}
注意:
1.@WebServlet不要加,在web项目中配置。因为是在项目中使用到,而不是全局。
postman
代替浏览器发送请求的工具
请求里面输入url,body选择raw->JSON,发送一个JSON格式的字符串
测试能否成功。
相关文章:
Day47
Day47 手写Spring-MVC之DispatcherServlet DispatcherServlet的思路: 前端传来URI,在TypeContainer容器类中通过uri得到对应的类描述类对象(注意:在监听器封装类描述类对象的时候,是针对于每一个URI进行封装的&#x…...
【面试系列】后端开发工程师 高频面试题及详细解答
欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来:详细讲解AIGC的概念、核心技术、…...

mac|浏览器链接不上服务器但可以登微信
千万千万千万不要没有关梯子直接关机,不然就会这样子呜呜呜 设置-网络,点击三个点--选择--位置--编辑位置(默认是自动) 新增一个,然后选中点击完成 这样就可以正常上网了...

Spring Cloud Alibaba之负载均衡组件Ribbon
一、什么是负载均衡? (1)概念: 在基于微服务架构开发的系统里,为了能够提升系统应对高并发的能力,开发人员通常会把具有相同业务功能的模块同时部署到多台的服务器中,并把访问业务功能的请求均…...

tkinter显示图片
tkinter显示图片 效果代码解析打开和显示图像 代码 效果 代码解析 打开和显示图像 def open_image():file_path filedialog.askopenfilename(title"选择图片", filetypes(("PNG文件", "*.png"), ("JPEG文件", "*.jpg;*.jpeg&q…...
000.二分查找算法题解目录
000.二分查找算法题解目录 69. x 的平方根(简单)34. 在排序数组中查找元素的第一个和最后一个位置(中等)...

数据资产赋能企业决策:通过精准的数据分析和洞察,构建高效的数据资产解决方案,为企业提供决策支持,助力企业实现精准营销、风险管理、产品创新等目标,提升企业竞争力
一、引言 在信息化和数字化飞速发展的今天,数据已成为企业最宝贵的资产之一。数据资产不仅包含了企业的基本信息,还蕴含了丰富的市场趋势、消费者行为和潜在商机。如何通过精准的数据分析和洞察,构建高效的数据资产解决方案,为企…...

【java开发环境】多版本jdk 自由切换window和linux
win10 一、准备 各种版本的jdk,按自己的需要下载。 我这里是需要jdk17和jdk8。 1、jdk17 下载:Java Downloads | Oracle,选择exe后缀文件 2、jdk8下 载:Java Downloads | Oracle,选择exe后缀文件 二、详细步骤 1、…...

MySQL实训项目——餐饮点餐系统
项目简介:餐饮点餐系统是一款为餐厅和顾客提供便捷点餐服务的在线平台。通过该系统,餐厅能够展示其菜单,顾客可以浏览菜品,并将其加入购物车或直接下单。系统还提供了订单管理功能,方便餐厅跟踪和处理顾客的订单。 1. …...

昇思MindSpore学习总结七——模型训练
1、模型训练 模型训练一般分为四个步骤: 构建数据集。定义神经网络模型。定义超参、损失函数及优化器。输入数据集进行训练与评估。 现在我们有了数据集和模型后,可以进行模型的训练与评估。 2、构建数据集 首先从数据集 Dataset加载代码࿰…...

AI时代创新潮涌,从探路到引路,萤石云引领千行百业创新
步入AI新时代,AI、云计算、大数据等技术迅速迭代,并日益融入经济社会发展各领域全过程,数字经济成为推动千行百业转型升级的重要驱动力量。 今年的政府工作报告提出,深入推进数字经济创新发展。积极推进数字产业化、产业数字化&a…...

计算机毕业设计Python深度学习美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js
Python美食推荐系统开题报告 一、项目背景与意义 随着互联网和移动技术的飞速发展,人们的生活方式发生了巨大变化,尤其是餐饮行业。在线美食平台如雨后春笋般涌现,为用户提供了丰富的美食选择。然而,如何在海量的餐饮信息中快速…...
【鸿蒙学习笔记】鸿蒙ArkTS学习笔记
应用开发导读:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/application-dev-guide-V5 这里写目录标题 基础组件通用属性容器组件Button 迭代完备 【鸿蒙培训】第1天・环境安装 【鸿蒙培训】第2天・装饰器・组件和页面…...

广东行政职业学院数据智能订单班开班暨上进双创工作室签约仪式圆满结束
为响应教育领域数字化与智能化浪潮这一变革,给学生提供更好的教育资源和实践机会,6月27日,“泰迪广东行政职业学院数据智能订单班开班仪式暨上进双创工作室签约授牌”在广东行政职业学院举行。广东行政职业学院智慧政务学院(电子信…...
python与matlab微分切片的区别
python python使用np中的linespace生成等间隔数值, import numpy as np numpy.linspace(start, stop, num50, endpointTrue, retstepFalse, dtypeNone, axis0)start:序列的起始值。stop:序列的结束值。如果 endpoint 为 True,该…...

MSPG3507——蓝牙接收数据显示在OLED,滴答定时器延时500MS
#include "ti_msp_dl_config.h" #include "OLED.h" #include "stdio.h"volatile unsigned int delay_times 0;//搭配滴答定时器实现的精确ms延时 void delay_ms(unsigned int ms) {delay_times ms;while( delay_times ! 0 ); } int a0; …...

Linux 安装 Redis 教程
优质博文:IT-BLOG-CN 一、准备工作 配置gcc:安装Redis前需要配置gcc: yum install gcc如果配置gcc出现依赖包问题,在安装时提示需要的依赖包版本和本地版本不一致,本地版本过高,出现如下问题:…...
【高考志愿】建筑学
目录 一、专业介绍 1.1 专业定义 1.2 专业培养目标 1.3 核心课程 二、就业方向和前景 2.1 就业方向 2.2 专业前景 三、报考注意 四、行业趋势与未来展望 五、建筑学专业排名 一、专业介绍 1.1 专业定义 建筑学,这一充满艺术与科技魅力的学科,…...

Kubernetes的发展历程:从Google内部项目到云原生计算的基石
目录 一、起源与背景 1.1 Google的内部项目 1.2 Omega的出现 二、Kubernetes的诞生 2.1 开源的决策 2.2 初期发布 三、Kubernetes的发展历程 3.1 社区的成长 3.2 生态系统的壮大 3.3 重大版本和功能 3.4 多云和混合云的支持 四、Kubernetes的核心概念 4.1 Pod 4.…...
/proc/config.gz
前言 有时候,我们想知道一个运行着的内核都打开了哪些编译选项,当然,查看编译环境的 .config 文件是一个不错的选择,除此之外,还有没有别的办法呢?当然有,那就是 /proc/config.gz。 一睹风采 …...

agent基础概念
agent是什么 我个人认为agent并没有一个所谓完美的定义,它是一个比较活的概念,就像是你眼中的一个机器人你希望它做什么事,和我眼中的机器人它解决事情的流程,其实是可以完全不同的,没有必要非得搞一个统一的概念或流程来概况它。但我们依然可以概况几个通用的词来描述它…...

力扣HOT100之二分查找:4. 寻找两个正序数组的中位数
这道题如果没有时间复杂度的限制的话,相当好做,但是这道题要求时间复杂度为O(log(m n)),思路很难想,我看了一圈题解,发现华南溜达虎的视频讲得还不错,我是参考他的思路写出来的,这里把他的思路…...
第七十三篇 从电影院售票到停车场计数:生活场景解析Java原子类精髓
目录 一、原子类基础:电影院售票系统1.1 传统售票的并发问题1.2 原子类解决方案 二、原子类家族:超市收银系统2.1 基础类型原子类2.2 数组类型原子类 三、CAS机制深度解析:停车场管理系统3.1 CAS工作原理3.2 车位计数器实现 四、高性能实践&a…...

在 Conda 环境下配置 Jupyter Notebook 环境和工作目录
作为数据科学家或Python开发者,Jupyter Notebook 是我们日常工作的得力工具。本文将详细介绍如何在 Conda 环境中配置 Jupyter Notebook,包括环境设置和工作目录管理,帮助你打造高效的工作流程。 为什么要在 Conda 环境中使用 Jupyter Noteb…...
算法训练第十天
232. 用栈实现队列 代码: class MyQueue(object):def __init__(self):self.arr1 []self.arr2 []def push(self, x):""":type x: int:rtype: None"""self.arr1.append(x)def pop(self):""":rtype: int""…...
MySQL Binlog 数据恢复全指南
MySQL Binlog 数据恢复全指南 一、Binlog 核心概念 1. 什么是 Binlog? Binlog(二进制日志)是 MySQL 记录所有修改数据的 SQL 语句的日志文件,采用二进制格式存储。它是 MySQL 最重要的日志之一,具有三大核心功能&am…...

Redis:Hash数据类型
🌈 个人主页:Zfox_ 🔥 系列专栏:Redis 🔥 Hash哈希 🐳 ⼏乎所有的主流编程语⾔都提供了哈希(hash)类型,它们的叫法可能是哈希、字典、关联数组、映射。在Redis中&#…...

图卷积网络:从理论到实践
图卷积网络(Graph Convolutional Networks, GCNs)彻底改变了基于图的机器学习领域,使得深度学习能够应用于非欧几里得结构,如社交网络、引文网络和分子结构。本文将解释GCN的直观理解、数学原理,并提供代码片段帮助您理…...
C++动态规划-线性DP
这是一套C线性DP题目的答案。如果需要题目,请私信我,我将会更新题干 P1:单子序列最大和 #include <bits/stdc.h> using namespace std; int n,A,B,C; int a[200005]; int s[200005]; int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)…...
一键更新依赖全指南:Flutter、Node.js、Kotlin、Java、Go、Python 等主流语言全覆盖
在现代软件开发中,依赖项扮演着至关重要的角色。保持依赖的最新状态不仅可以获得新特性和性能优化,还能修复已知安全漏洞。但在不同语言和框架中,依赖管理的方式差异很大。本篇文章将系统性讲解如何在各主流语言中实现“一键更新依赖”。 &am…...