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。 一睹风采 …...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...