手写SpringMVC(基本框架)
服务器启动阶段处理
分析服务器启动阶段都都需要初始化什么?
1.初始化Spring容器
- 组件扫描包下的类纳入IOC容器管理
- 创建视图解析器对象
- 创建所有的拦截器对象
- 扫描这和包下的所有类org.myspringmvc.web.servlet.mvc.method.annotation,全部实例化,纳入IoC容器管理
Spring容器:ApplicationContext
SpringWeb容器:WebApplicationContext
组件扫描
springmvc.xml文件
<?xml version="1.0" encoding="utf-8" ?><beans><!--拦截器视图解析器组件扫描--><component-scan base-package="org.springmvc.oa.controller"/>
<!-- 视图解析器--><bean class="org.springmvc.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀--><property name="prefix"><value>/WEB-INF/jsp/</value></property>
<!-- 后缀--><property name="suffix"><value>.jsp</value></property></bean><!-- 拦截器--><interceptors><bean class="org.springmvc.oa.interceptors.Interceptor1"></bean><bean class="org.springmvc.oa.interceptors.Interceptor2"></bean></interceptors>
</beans>
添加解析XML文件的依赖
<!--dom4j-->
<dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version>
</dependency>
<!--jaxen-->
<dependency><groupId>jaxen</groupId><artifactId>jaxen</artifactId><version>1.1.6</version>
</dependency>
ApplicationContext
public class ApplicationContext {private Map<String, Object> beanMap = new HashMap<>();public ApplicationContext(String xmlPath) throws Exception {// 组件扫描SAXReader saxReader = new SAXReader();Document document = saxReader.read(new File(xmlPath));Element componentScanElement = (Element)document.selectSingleNode("/beans/context:component-scan");String basePackage = componentScanElement.attributeValue("base-package");System.out.println("组件扫描:" + basePackage);componentScan(basePackage);System.out.println("Spring Web容器当下状态:" + beanMap);}private void componentScan(String basePackage) throws Exception{String dirPath = Thread.currentThread().getContextClassLoader().getResource(basePackage.replace(".", "/")).getPath();File file = new File(URLDecoder.decode(dirPath));if(file.isDirectory()){File[] files = file.listFiles();for (File classFile : files){if(classFile.getName().endsWith(".class")){String className = basePackage + "." + classFile.getName().substring(0, classFile.getName().lastIndexOf("."));Class<?> clazz = Class.forName(className);Constructor<?> defaultCon = clazz.getDeclaredConstructor();Object bean = defaultCon.newInstance();beanMap.put(firstCharLowerCase(clazz.getSimpleName()), bean);}}}}private String firstCharLowerCase(String simpleName) {return simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);}public Object getBean(String beanName){return beanMap.get(beanName);}
}
组件扫描的beanMap结果
WebApplicationContext
package org.springmvc.web.context;import jakarta.servlet.ServletContext;
import org.dom4j.DocumentException;
import org.springmvc.context.ApplicationContext;import java.lang.reflect.InvocationTargetException;public class WebApplicationContext extends ApplicationContext {private ServletContext servletContext;private String springMvcConfigPath;public WebApplicationContext() {}public WebApplicationContext(ServletContext servletContext, String springMvcConfigPath) throws DocumentException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {super(springMvcConfigPath);this.servletContext = servletContext;this.springMvcConfigPath = springMvcConfigPath;}/*** 获取* @return servletContext*/public ServletContext getServletContext() {return servletContext;}/*** 设置* @param servletContext*/public void setServletContext(ServletContext servletContext) {this.servletContext = servletContext;}/*** 获取* @return springMvcConfigPath*/public String getSpringMvcConfigPath() {return springMvcConfigPath;}/*** 设置* @param springMvcConfigPath*/public void setSpringMvcConfigPath(String springMvcConfigPath) {this.springMvcConfigPath = springMvcConfigPath;}public String toString() {return "WebApplicationContext{servletContext = " + servletContext + ", springMvcConfigPath = " + springMvcConfigPath + "}";}
}
创建视图解析器对象
InternalResourceViewResolver
内部资源视图解析器
package org.springmvc.web.servlet.view;import org.springmvc.web.servlet.View;
import org.springmvc.web.servlet.ViewResolver;import java.util.Locale;/*内部资源解析器*/
public class InternalResourceViewResolver implements ViewResolver {String prefix;String suffix;public InternalResourceViewResolver() {}public InternalResourceViewResolver(String prefix, String suffix) {this.prefix = prefix;this.suffix = suffix;}/*将逻辑试图名字 转换为物理视图名称 并以View对象返回*/@Overridepublic View resolveViewName(String viewName, Locale locale) throws Exception {return new InternalResourceView("text/html;charset-UTF-8", prefix+viewName+suffix);}/*** 获取* @return prefix*/public String getPrefix() {return prefix;}/*** 设置* @param prefix*/public void setPrefix(String prefix) {this.prefix = prefix;}/*** 获取* @return suffix*/public String getSuffix() {return suffix;}/*** 设置* @param suffix*/public void setSuffix(String suffix) {this.suffix = suffix;}public String toString() {return "InternalResourceViewResolver{prefix = " + prefix + ", suffix = " + suffix + "}";}/*** 获取* @return suffix*//*** 获取* @return prefix*/}
创建视图解析器对象
private void createViewResolver(Element viewResolverElement) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {String viewResolverClassName=viewResolverElement.attributeValue("class");System.out.println("视图解析器类名"+viewResolverClassName);Class clazz= Class.forName(viewResolverClassName);Object bean = clazz.newInstance();//bean节点下子节点propertyList<Element> propertyElements=viewResolverElement.elements(Constant.PROPERTY_TAG_NAME);for(Element propertyElement:propertyElements){//获取属性名String fieldName=propertyElement.attributeValue(Constant.PROPERTY_NAME);String value=propertyElement.element(Constant.PROPERTY_VALUE).getTextTrim();//将属性名转为set方法String setMethodName=fieldNameToSetMethod(fieldName);//通过反射机制调用set方法Method setMethod = clazz.getDeclaredMethod(setMethodName,String.class);setMethod.invoke(bean,value);}beanMap.put(Constant.VIEW_RESOLVER, bean);}
创建拦截器对象
private void createInteceptor(Element interceptorElement) throws ClassNotFoundException, InstantiationException, IllegalAccessException {List<Element> interceptorElements=interceptorElement.elements("bean");List<HandlerInterceptor> interceptors=new ArrayList<>();for(Element interceptor:interceptorElements){Class<?> clazz=Class.forName(interceptor.attributeValue("class"));Object bean=clazz.newInstance();interceptors.add((HandlerInterceptor)bean);}beanMap.put(Constant.INTERCEPROTS,interceptors);}
2.初始化HandlerMapping和初始化HandlerAdapter
初始化annotation包下所有类的实例
private void createHandlerMapping(String defaultPackage,Map<RequestMappingInfo, HandlerMethod>map) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//System.out.println(defaultPackage);// 将这个包下所有的类实例化:org.myspringmvc.web.servlet.mvc.method.annotation//获取绝对路径String dirPath=Thread.currentThread().getContextClassLoader().getResource(defaultPackage.replace('.', '/')).getPath();File file=new File(URLDecoder.decode(dirPath));//获取里面所有的子文件if(file.isDirectory()){File[] files = file.listFiles();for(File classFile : files){if(classFile.getName().endsWith(Constant.SUFFER_CLASS)){//全类名String className=defaultPackage+"."+classFile.getName().substring(0,classFile.getName().lastIndexOf("."));Class<?>clazz=Class.forName(className);if(HandlerMapping.class.isAssignableFrom(clazz)){Constructor<?>defaultCon= clazz.getDeclaredConstructor(Map.class);Object bean=defaultCon.newInstance(map);beanMap.put(Constant.HANDLER_MAPPING, bean);}if(HandlerAdapter.class.isAssignableFrom(clazz)){Constructor<?>defaultCon= clazz.getDeclaredConstructor();Object bean=defaultCon.newInstance();beanMap.put(Constant.HANDLER_ADAPTER, bean);}}}}}
2.初始化Servlet对象
DispatchServlet init()
public void init(){//找到springmvc.xml文件/*<init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param>*///根据以上配置springmvc.xml文件//获取SpringConfig对象(Servlet配置信息对象 该对象由web容器自动创建 并且将其传递给init方法// )ServletConfig servletConfig = this.getServletConfig();String contextConfigLocation = servletConfig.getInitParameter(Constant.CONTEXT_CONFIG_LOCATION);String springMvcXmlPath=getSpringMvcXmlPath(contextConfigLocation);System.out.println("Spring MVC配置文件路径解析完成:" + springMvcXmlPath);//初始化Spring Web容器WebApplicationContext webApplicationContext = null;try {webApplicationContext = new WebApplicationContext(this.getServletContext(), springMvcXmlPath);} catch (DocumentException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}this.getServletContext().setAttribute(Constant.WEB_APPLICATION_CONTEXT, webApplicationContext);//初始化HandlerMappingthis.handlerMapping=(HandlerMapping)webApplicationContext.getBean(Constant.HANDLER_MAPPING);//初始化HandlerAdapterthis.handlerAdapter=(HandlerAdapter)webApplicationContext.getBean(Constant.HANDLER_ADAPTER);//初始化试图解析器this.viewResolver=(ViewResolver)webApplicationContext.getBean(Constant.VIEW_RESOLVER);}private String getSpringMvcXmlPath(String contextConfigLocation) {if(contextConfigLocation.startsWith(Constant.CLASSPATH)){String path=contextConfigLocation.substring(Constant.CLASSPATH.length()).trim();//类路径中找String springMvcXmlPath=Thread.currentThread().getContextClassLoader().getResource(path).getPath();// 对路径解码,防止路径中有 % 等字符。return URLDecoder.decode(springMvcXmlPath, Charset.defaultCharset());}return null;}
doDispath方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {try {doDispatch(req, resp);} catch (Exception e) {throw new RuntimeException(e);}}/*** 处理请求的核心方法* @param request* @param response* @throws ServletException* @throws IOException*/private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {//访问浏览器才能断点到这//请求对象获取对应的处理器执行连对象HandlerExecutionChain mappedHandler=handlerMapping.getHandler(request);//获取处理器适配器对象HandlerAdapter adapter = this.handlerAdapter;//3.执行拦截器中的preHandle方法if(!mappedHandler.applyPreHandle(request,response)){return;//false的话}//4.执行处理器方法 返回ModelAndViewModelAndView mv=adapter.handle(request,response,mappedHandler.getHandler());System.out.println("处理器执行连对象:"+mappedHandler);//5.执行拦截器中postHanldermappedHandler.applyPostHandle(request,response,mv);//6.试图解析器 逻辑试图名称转为物理视图名称View view=viewResolver.resolveViewName(mv.getView().toString(),request.getLocale());view.render(mv.getModel(),request,response);//执行拦截器渲染之后的afterCompletetion方法mappedHandler.triggerAfterCompletion(request,response,null);}
根据请求获取处理器执行链
HandlerExecutionChain mappedHandler=handlerMapping.getHandler(request);
HandlerMapping
public interface HandlerMapping {/*** ClassName: HandlerMapping* Description: 主要是通过请求获取对应的处理器执行链。* Datetime: 2024/4/2 8:50* Author: 老杜@动力节点* Version: 1.0*/HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
HandlerMethod
package org.springmvc.web.method;import java.lang.reflect.Method;/*处理器方法 controller*/
public class HandlerMethod {/*处理器对象*/private Object handler;/*** 要执行的方法*/private Method method;public HandlerMethod() {}public HandlerMethod(Object handler, Method method) {this.handler = handler;this.method = method;}/*** 获取* @return handler*/public Object getHandler() {return handler;}/*** 设置* @param handler*/public void setHandler(Object handler) {this.handler = handler;}/*** 获取* @return method*/public Method getMethod() {return method;}/*** 设置* @param method*/public void setMethod(Method method) {this.method = method;}public String toString() {return "HandlerMethod{handler = " + handler + ", method = " + method + "}";}
}
RequestMappingInfo
package org.springmvc.web.servlet;import java.util.Objects;public class RequestMappingInfo {private String requestURI;@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;RequestMappingInfo that = (RequestMappingInfo) o;return Objects.equals(requestURI, that.requestURI) && Objects.equals(method, that.method);}@Overridepublic int hashCode() {return Objects.hash(requestURI, method);}//GET POST PUT DELETEprivate String method;public RequestMappingInfo() {}public RequestMappingInfo(String requestURI, String method) {this.requestURI = requestURI;this.method = method;}/*** 获取* @return requestURI*/public String getRequestURI() {return requestURI;}/*** 设置* @param requestURI*/public void setRequestURI(String requestURI) {this.requestURI = requestURI;}/*** 获取* @return method*/public String getMethod() {return method;}/*** 设置* @param method*/public void setMethod(String method) {this.method = method;}public String toString() {return "RequestMappingInfo{requestURI = " + requestURI + ", method = " + method + "}";}
}
RequestMappingHandlerMapping
package org.springmvc.web.servlet.mvc.method.annotation;import jakarta.servlet.http.HttpServletRequest;
import org.springmvc.web.constant.Constant;
import org.springmvc.web.context.WebApplicationContext;
import org.springmvc.web.method.HandlerMethod;
import org.springmvc.web.servlet.*;import java.util.List;
import java.util.Map;/*处理器映射器 专门为 @RequestMapping 注解的类服务的处理器映射器通过前端提交的请求 来底层映射要执行的HandlerMethod*/
public class RequestMappingHandlerMapping implements HandlerMapping {private Map<RequestMappingInfo, HandlerMethod> map;/*创建HandlerMapping对象时 给map赋值*/public RequestMappingHandlerMapping(Map<RequestMappingInfo, HandlerMethod> map) {this.map = map;}@Overridepublic HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//通过request对象 获取请求路径,请求方式 封装程RequestMappingInfoRequestMappingInfo requestMappingInfo=new RequestMappingInfo(request.getServletPath(),request.getMethod());//******************必须重写 如果补充写 key是对象 对于相同请求创建多个对象 可能认为是不同的HandlerExecutionChain handlerExecutionChain =new HandlerExecutionChain();//给执行连设置handlerMethodhandlerExecutionChain.setHandler(map.get(requestMappingInfo));//给执行连设置拦截器//通过Spring容器WebApplicationContext webApplicationContext=(WebApplicationContext)request.getServletContext().getAttribute(Constant.WEB_APPLICATION_CONTEXT);List<HandlerInterceptor> interceptors=(List<HandlerInterceptor>)webApplicationContext.getBean(Constant.INTERCEPROTS);handlerExecutionChain.setInterceptors(interceptors);return handlerExecutionChain;}
}
处理器执行链对象
注意:
public RequestMappingHandlerMapping(Map<RequestMappingInfo, HandlerMethod> map) {
this.map = map;
}包扫描的时候初始化RequestMappingHandlerMapping时 要传入Map对象 所以包扫描要改为下面的代码
private Map<RequestMappingInfo, HandlerMethod> componentScan(String basePackage) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Map<RequestMappingInfo, HandlerMethod>handlerMethodMap=new HashMap<>();//获取绝对路径String dirPath=Thread.currentThread().getContextClassLoader().getResource(basePackage.replace(".","/")).getPath();File file=new File(URLDecoder.decode(dirPath));//封装为文件//获取里面所有的子文件if(file.isDirectory()){File[] files = file.listFiles();for(File classFile:files){if(classFile.getName().endsWith(Constant.SUFFER_CLASS)){String className=basePackage+"."+classFile.getName().substring(0,classFile.getName().lastIndexOf("."));Class<?> clazz = Class.forName(className);Constructor<?>defaultCon= clazz.getDeclaredConstructor();//System.out.println("简单类名"+clazz.getSimpleName());Object bean=defaultCon.newInstance();beanMap.put(firstCharLowerCase(clazz.getSimpleName()), bean);//UserController 默认beanName 首字母小写//获取类上面的注解 @Controller注解包围if(clazz.isAnnotationPresent(Controller.class)){//被Controller注解包裹//获取类中所有的方法Method []methods=clazz.getDeclaredMethods();for(Method method:methods){//如果该注解被RequestMapping注解包裹if(method.isAnnotationPresent(RequestMapping.class)){RequestMapping requestMapping=method.getAnnotation(RequestMapping.class);String requestURI=requestMapping.value()[0];String requestMethod=requestMapping.method().toString();// GETRequestMappingInfo requestMappingInfo=new RequestMappingInfo(requestURI,requestMethod);HandlerMethod handlerMethod=new HandlerMethod();//请求的方法handlerMethod.setHandler(bean);handlerMethod.setMethod(method);handlerMethodMap.put(requestMappingInfo,handlerMethod);}}}}}}
执行拦截器的中preHandler方法
public boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i = 0; i <interceptors.size() ; i++) {HandlerInterceptor handlerInterceptor = interceptors.get(i);boolean result=handlerInterceptor.preHandle(request,response,handler);if(!result){//执行拦截器的AfterCompletiontriggerAfterCompletion(request,response,handler);return false;}}return true;}
.执行处理器方法 返回ModelAndView
public interface HandlerAdapter {ModelAndView handle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception;
}public class RequestMappingHandlerAdapter implements HandlerAdapter {@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//需要调用处理器方法HandlerMethod handlerMethod = (HandlerMethod)handler;//获取控制器Object controller=handlerMethod.getHandler();//获取调用的方法Method method=handlerMethod.getMethod();ModelMap modelMap=new ModelMap();//通过反射机制调用String viewName=(String)method.invoke(controller,modelMap);//自己写的目前需要 Controller指定ModelMap//还有一个特殊要求 要求返回逻辑试图名称ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName(viewName);modelAndView.setModel(modelMap);return modelAndView;}
}package org.springmvc.ui;import java.util.LinkedHashMap;public class ModelMap extends LinkedHashMap<String, Object> {public ModelMap() {}public ModelMap addAttribute(String name, String value) {this.put(name,value);return this;}
}package org.springmvc.oa.controller;import org.springmvc.stereotype.Controller;
import org.springmvc.ui.ModelMap;
import org.springmvc.web.bind.annotation.RequestMapping;
import org.springmvc.web.bind.annotation.RequestMethod;@Controller
public class UserController {@RequestMapping(value ="/index", method = RequestMethod.GET)public String index(ModelMap modelMap){modelMap.put("name","liwu");return "index";}
}
执行拦截器中postHanlder
public void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {for(int i=interceptors.size()-1;i>=0;i--){HandlerInterceptor handlerInterceptor = interceptors.get(i);handlerInterceptor.postHandle(request,response,handler,mv);}}
视图解析器 逻辑试图名称转为物理视图名称
public interface ViewResolver {/*解析逻辑视图名称,返回视图对象*/View resolveViewName(String viewName, Locale locale) throws Exception;}public View resolveViewName(String viewName, Locale locale) throws Exception {return new InternalResourceView("text/html;charset-UTF-8", prefix+viewName+suffix);}public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {//设置响应类型response.setContentType(contentType);//将model数据存储到request域中//默认情况下跳转到视图以转发方式model.forEach((key,value)->{request.setAttribute(key,value);});request.getRequestDispatcher(path).forward(request,response);}
执行拦截器渲染之后的afterCompletetion方法
public void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {for(int i=interceptors.size()-1;i>=0;i--){HandlerInterceptor handlerInterceptor = interceptors.get(i);handlerInterceptor.afterCompletion(request, response,handler, (Exception) o);}}
SSM整合
引入相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<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>org.springmvc</groupId><artifactId>ssm-annotation</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><!--springmvc--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.1.4</version></dependency><!--spring jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.1.4</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.15</version></dependency><!--mybatis spring--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>3.0.3</version></dependency><!--mysql驱动--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.3.0</version></dependency><!--德鲁伊连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.22</version></dependency><!--jackson--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.17.0</version></dependency><!--servlet api--><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>6.0.0</version><scope>provided</scope></dependency><!--logback--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.5.3</version></dependency><!--thymeleaf和spring6的整合依赖--><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring6</artifactId><version>3.1.2.RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>RELEASE</version><scope>compile</scope></dependency></dependencies><properties><maven.compiler.source>21</maven.compiler.source><maven.compiler.target>21</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties></project>
创建包结构
创建webapp目录
Spring整合Mybatis
编写mybatis.properties
mybatis.driverClassName=com.mysql.cj.jdbc.Driver
mybatis.url=jdbc:mysql://localhost:3306/db03?useSSL=false&allowPublicKeyRetrieval=true
mybatis.username=root
mybatis.password=123456
mybatis.mapperLocations=classpath*:com/gao/ssm/dao/*Mapper.xml
MybatisProperties
package com.gao.ssm.dao;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;@Component
@PropertySource("classpath:mybatis.properties")
public class MybatisProperties {@Value("${mybatis.driverClassName}")private String driverClassName;@Value("${mybatis.url}")private String url;@Value("${mybatis.username}")private String username;@Value("${mybatis.password}")private String password;@Value("${mybatis.mapperLocations}")private String mapperLocations;public MybatisProperties() {}public MybatisProperties(String driverClassName, String url, String username, String password, String mapperLocations) {this.driverClassName = driverClassName;this.url = url;this.username = username;this.password = password;this.mapperLocations = mapperLocations;}/*** 获取* @return driverClassName*/public String getDriverClassName() {return driverClassName;}/*** 设置* @param driverClassName*/public void setDriverClassName(String driverClassName) {this.driverClassName = driverClassName;}/*** 获取* @return url*/public String getUrl() {return url;}/*** 设置* @param url*/public void setUrl(String url) {this.url = url;}/*** 获取* @return username*/public String getUsername() {return username;}/*** 设置* @param username*/public void setUsername(String username) {this.username = username;}/*** 获取* @return password*/public String getPassword() {return password;}/*** 设置* @param password*/public void setPassword(String password) {this.password = password;}/*** 获取* @return mapperLocations*/public String getMapperLocations() {return mapperLocations;}/*** 设置* @param mapperLocations*/public void setMapperLocations(String mapperLocations) {this.mapperLocations = mapperLocations;}public String toString() {return "MybatisProperties{driverClassName = " + driverClassName + ", url = " + url + ", username = " + username + ", password = " + password + ", mapperLocations = " + mapperLocations + "}";}
}
MybatisConfig
package com.gao.ssm.config;import com.alibaba.druid.pool.DruidDataSource;
import com.gao.ssm.dao.MybatisProperties;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;import javax.sql.DataSource;
import java.io.IOException;@Configuration
@ComponentScan("com.gao.ssm.dao")
@MapperScan("com.gao.ssm.dao")
public class MybatisConfig {@Autowiredprivate MybatisProperties mybatisProperties;@Beanpublic DataSource dataSource(){DruidDataSource dataSource=new DruidDataSource();dataSource.setUsername(mybatisProperties.getUsername());dataSource.setPassword(mybatisProperties.getPassword());dataSource.setUrl(mybatisProperties.getUrl());dataSource.setDriverClassName(mybatisProperties.getDriverClassName());return dataSource;}@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws IOException {SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);ResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();Resource[]resources=resolver.getResources(mybatisProperties.getMapperLocations());sqlSessionFactoryBean.setMapperLocations(resources);return sqlSessionFactoryBean;}@Beanpublic PlatformTransactionManager platformTransactionManager(DataSource dataSource){DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;}
}
SpringConfig
package com.gao.ssm.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration
@ComponentScan("com.gao.ssm.service")
@EnableTransactionManagement
@Import({MybatisConfig.class})
public class SpringConfig {
}
Spring整合Spring MVC
package com.gao.ssm.config;import jakarta.servlet.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;@Configuration
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {/*配置Spring的配置文件*/@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[0];}/*SpringMVC配置文件*/@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}/*配置DispatcherServlet的映射规则,即url-pattern*/@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}/*** Spring的配置* @return*/@Overrideprotected Filter[] getServletFilters() {CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();characterEncodingFilter.setEncoding("UTF-8");characterEncodingFilter.setForceRequestEncoding(true);characterEncodingFilter.setForceResponseEncoding(true);//!--隐藏的HTTP请求方式过滤器 字符编码过滤器之后-->HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};}}
SpringMvcConfig
package com.gao.ssm.config;import com.gao.ssm.interceptor.MyInterceptor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;import java.util.List;
import java.util.Properties;@Configuration
@ComponentScan("com.gao.ssm.handler")
@Import({SpringConfig.class})
@EnableWebMvc
//开启注解驱动
public class SpringMvcConfig implements WebMvcConfigurer {@Overridepublic void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {SimpleMappingExceptionResolver simpleHandlerExceptionResolver=new SimpleMappingExceptionResolver();Properties prop = new Properties();prop.setProperty("java.lang.Exception", "tip");simpleHandlerExceptionResolver.setExceptionMappings(prop);simpleHandlerExceptionResolver.setExceptionAttribute("e");resolvers.add(simpleHandlerExceptionResolver);}@Beanpublic ThymeleafViewResolver getViewResolver(SpringTemplateEngine springTemplateEngine) {ThymeleafViewResolver resolver = new ThymeleafViewResolver();resolver.setTemplateEngine(springTemplateEngine);resolver.setCharacterEncoding("UTF-8");resolver.setOrder(1);return resolver;}@Beanpublic SpringTemplateEngine templateEngine(ITemplateResolver iTemplateResolver) {SpringTemplateEngine templateEngine = new SpringTemplateEngine();templateEngine.setTemplateResolver(iTemplateResolver);return templateEngine;}public void addInterceptors(InterceptorRegistry registry) {MyInterceptor myInterceptor = new MyInterceptor();registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/test");}@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/index").setViewName("index");}@Beanpublic ITemplateResolver templateResolver(ApplicationContext applicationContext) {SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();resolver.setApplicationContext(applicationContext);resolver.setPrefix("/WEB-INF/thymeleaf/");resolver.setSuffix(".html");resolver.setTemplateMode(TemplateMode.HTML);resolver.setCharacterEncoding("UTF-8");resolver.setCacheable(false);//开发时关闭缓存,改动即可生效return resolver;}@Override//开启静态资源处理public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}
}
添加事务控制
@Configuration
@ComponentScan("com.gao.ssm.service")
@EnableTransactionManagement
@Import({MybatisConfig.class})
public class SpringConfig {
}@Transactional()
@Service
public class EmpServiceImpl implements EmpService{
pojo类编写
package com.gao.ssm.bean;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDate;
import java.time.LocalDateTime;/*** 员工实体类*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {private Integer id; //IDprivate String username; //用户名private String password; //密码private String name; //姓名private Short gender; //性别 , 1 男, 2 女private String image; //图像urlprivate Short job; //职位 , 1 班主任 , 2 讲师 , 3 学工主管 , 4 教研主管 , 5 咨询师private LocalDate entrydate; //入职日期private Integer deptId; //部门IDprivate LocalDateTime createTime; //创建时间private LocalDateTime updateTime; //修改时间
}
dao编写
package com.gao.ssm.dao;import com.gao.ssm.bean.Emp;
import org.apache.ibatis.annotations.Mapper;import java.util.List;
public interface EmpDao {List<Emp> listAll();Emp listOne(Emp emp);void add(Emp emp);
}
service编写
package com.gao.ssm.service;import com.gao.ssm.bean.Emp;import java.util.List;public interface EmpService{public void register(Emp emp);public List<Emp> listAll();}
package com.gao.ssm.service;import com.gao.ssm.bean.Emp;
import com.gao.ssm.dao.EmpDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Transactional()
@Service
public class EmpServiceImpl implements EmpService{@Autowiredprivate EmpDao empDao;@Overridepublic void register(Emp emp) {empDao.add(emp);}@Overridepublic List<Emp> listAll() {return empDao.listAll();}
}
handler编写
package com.gao.ssm.handler;import com.gao.ssm.bean.Emp;
import com.gao.ssm.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/emp")
public class EmpController {@Autowiredprivate EmpService empService;@RequestMapping("/list")public String list(){return empService.listAll().toString();}
}
EmpMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//MyBatis//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.gao.ssm.dao.EmpDao"><!-- 查询所有员工 --><select id="listAll" resultType="com.gao.ssm.bean.Emp">SELECT * FROM emp</select><!-- 根据 ID 查询单个员工 --><select id="listOne" resultType="com.gao.ssm.bean.Emp" parameterType="java.lang.Integer">SELECT * FROM emp WHERE id = #{id}</select><!-- 添加员工,返回主键 ID --><insert id="add" parameterType="com.gao.ssm.bean.Emp" useGeneratedKeys="true" keyProperty="id">INSERT INTO emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)VALUES (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})</insert></mapper>
测试
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>ssm整合</title><!--引入vue--><script th:src="@{/static/js/vue3.4.21.js}"></script><!--引入axios--><script th:src="@{/static/js/axios.min.js}"></script>
</head>
<body>
<div id="app"><button @click="getMessage">查询所有用户</button><h1>{{message}}</h1>
</div>
<script th:inline="javascript">Vue.createApp({data(){return {message : '很多信息'}},methods : {async getMessage(){console.log("------------查询")let response = await axios.get("/ssm/emp/list")console.log(response)this.message = response.data}}}).mount("#app")
</script>
</body>
</html>
相关文章:
手写SpringMVC(基本框架)
服务器启动阶段处理 分析服务器启动阶段都都需要初始化什么? 1.初始化Spring容器 组件扫描包下的类纳入IOC容器管理创建视图解析器对象创建所有的拦截器对象扫描这和包下的所有类org.myspringmvc.web.servlet.mvc.method.annotation,全部实例化&#…...
JS-OCR-demo加载本地文件
背景: 在了解 Tesseract 的识别效果的时候,有个demo项目很好用。有个小毛病,就是没事都要从摄像头抓取图片,然后进行识别。如果可以从本地读取图,就更方便了。 实现: 下载项目代码:https://gi…...
MySQL 表的约束(一)
文章目录 表的约束空属性默认值列描述zerofill主键总结 表的约束 1. 为什么要有表的约束? 因为要保证数据的完整性和可约束性,合法性 空属性 两个值:null(默认的)和not null(不为空)数据库默认字段基本都是字段为空…...
论文导读 - 基于大规模测量与多任务深度学习的电子鼻系统实现目标识别、浓度预测与状态判断
基于大规模测量与多任务深度学习的电子鼻系统实现目标识别、浓度预测与状态判断 原论文地址:https://www.sciencedirect.com/science/article/abs/pii/S0925400521014830 引用此论文(GB/T 7714-2015): WANG T, ZHANG H, WU Y, …...
力扣hot100_子串_python版本
一、560. 和为 K 的子数组 思路:这就是一道典型的前缀和的题代码: class Solution:def subarraySum(self, nums: List[int], k: int) -> int:presum [0] * (len(nums) 1)for i, x in enumerate(nums):presum[i 1] presum[i] x # 前缀和序列需要n1个ans 0…...
cached-property - 类属性缓存装饰器
本文翻译整理自:https://github.com/pydanny/cached-property 文章目录 一、关于 cached-property相关链接资源关键功能特性 二、安装三、使用指南1、基础用法2、手动清除缓存3、线程安全版本4、异步支持5、缓存超时(TTL) 四、致谢 一、关于…...
「Mac畅玩AIGC与多模态03」部署篇02 - 在 Mac 上部署 Dify
一、概述 本篇介绍如何在 macOS 环境下本地部署 Dify 平台,作为多模型协同与工作流集成的可视化应用服务。Dify 提供了模型调用、对话管理、知识库问答、插件服务等功能,可与 Ollama、OpenAI、DeepSeek 等推理后端集成,适用于本地智能体应用的快速搭建与扩展。 二、部署流…...
扩散模型和马尔科夫链
1. 扩散模型的基本原理 扩散模型的灵感来源于热力学扩散(如一滴墨水在水中逐渐扩散的过程),其核心分为两个阶段: 前向过程(Forward Process):逐步向数据添加噪声,直到数据完全变为随…...
Dify框架面试内容整理-Dify如何处理知识库的集成?
Dify 在知识库集成方面采用了“检索增强生成(RAG)”的技术架构,核心实现思路如下: 一、知识库集成的整体流程 Dify处理知识库集成通常包括以下关键步骤: 文档上传↓...
第35课 常用快捷操作——用“鼠标左键”拖动图元
概述 拖动某个图元,是设计过程中常需要用到的操作,我们可以在原理图中拖动某个元器件符号,也可以在PCB图中拖动某个焊盘。 和常用的软件类似,用按住鼠标左键的方式来完成拖动操作。 用鼠标左键拖动图元 在想要拖动的图元上&…...
复盘笔记1
以下是一份专业股市投资操盘手的复盘清单,涵盖市场分析、交易策略、风险管理等核心环节,帮助系统化梳理每日交易并优化次日决策: --- ### **一、市场整体复盘** 1. **指数与成交量分析** - 主要指数表现(上证、深证、创业板、科…...
海思dump图原理
在海思中是用指令进行对应的dump。 例如./vi_chn_dump 0 0 1 1 第一个指令代表是dump哪里的数据。 第一个0代表是vi_pipe。 第二个0代表vi_chn。 第一个1代表需要dump帧的数量。 第二个dump代表dump帧的位置,如果是0表示dump的是在所有ISP模块后面的数据࿰…...
C++:STL——list
一简介 底层是一个带头双向循环列表 二、成员函数 (1)构造函数 三、迭代器 四、修饰函数 (1)insert 插入和删除不再使用下标,而是使用迭代器指针作为要插入位置的形参,这是因为:vector是连续的…...
在Azure Databricks中实现缓慢变化维度(SCD)的三种类型
在Azure Databricks中使用PySpark实现缓慢变化维度(SCD)的三种核心类型,需结合Spark SQL和DataFrame API的特性,并利用Delta Lake的事务支持。以下是具体设计与实现步骤,以及测试用例: 通过以下步骤&#…...
Segment Anything in Images and Videos
目录 摘要 Abstract SAM2 模型框架 图像编码器 记忆机制 提示编码器和掩码解码器 实验 代码 总结 摘要 SAM2是基于Meta公司推出的Segment Anything Model升级而来的先进分割模型。它在SAM的基础上,通过引入记忆注意力模块和优化图像编码器等改进…...
C++之异常
目录 一、异常的概念及使用 1.1、异常的概念 1.2、异常的抛出和捕获 1.3、栈展开 1.4、查找匹配的处理代码 1.5、异常重新抛出 1.6、异常安全问题 1.7、异常规范 1.8、C异常的优缺点 二、标准库的异常 一、异常的概念及使用 1.1、异常的概念 异常处理机制允许程序中…...
服务器不能复制粘贴文件的处理方式
1.打开远程的服务器,在服务器的任务栏随便一块空白处右击鼠标,选择“启动任务管理器”。 2.在打开的任务管理器中,我们找到“rdpclip.exe”这个进程,如果没有找到那么如图所示 任务管理器–文件–运行新任务,然后在弹出的对话框内输入rdpclip.exe 如下图࿱…...
Golang | 搜索表达式
// (( A | B | C ) & D ) | E & (( F | G ) & H )import "strings"// 实例化一个搜索表达式 func NewTermQuery(field, keyword string) *TermQuery {return &TermQuery{Keyword: &Keyword{Field: field, Word: keyword},} }func (tq *TermQuery…...
【速写】conda安装(linux)
序言 昨天叶凯浩空降(全马241),降维打击,10分24秒断层夺冠。 夏潇阳10分53秒绝杀小崔10分54秒第2,小崔第3,均配都在3’30"以内,即便我是去年巅峰期也很难跑出这种水平。我就知道他去年大…...
linux两个特殊的宏 _RET_IP_ 和_THIS_IP_ 实现
本文探讨了Linux环境下两个特殊的宏,_RET_IP_和_THIS_IP_,它们分别用于获取当前函数的返回地址和当前指令指针的地址。 1、宏定义 我们先看它们的宏定义 include./linux/kernel.h#define _RET_IP_ (unsigned long)__builtin_return_address(0)#define _THIS_IP_ ({ __labe…...
开源|上海AILab:自动驾驶仿真平台LimSim Series,兼容端到端/知识驱动/模块化技术路线
导读 随着自动驾驶技术快速发展,有效的仿真环境成为验证与增强这些系统的关键。来自上海人工智能实验室的研究团队推出了LimSim Series——一个革命性的自动驾驶仿真平台,它巧妙解决了行业面临的三大挑战:仿真精度与持续时间的平衡、功能性与…...
全栈黑暗物质:可观测性之外的非确定性调试
一、量子计算的测不准Bug 1. 经典 vs. 量子系统的错误模式 量子程序崩溃的观测影响: 调试方法崩溃复现率观测干扰度日志打印12%35%断点调试5%78%无侵入跟踪27%9%量子态层析成像63%2% 二、量子调试工具箱 1. 非破坏性观测协议 # 量子程序的无干扰快照 from qiski…...
光耦、继电器
一、光耦 1.什么是光耦? ①图一:Ic受控于Ib,间接受控于Ia ②如果Va和Vb是隔离的两个电压系统该咋控制?可以利用光耦来控制,让两边建立关系 2.光电耦合器的基本原理 ①是以光为媒介来传输电信号的器件,通常把发光器…...
使用Three.js搭建自己的3Dweb模型(从0到1无废话版本)
教学视频参考:B站——Three.js教学 教学链接:Three.js中文网 老陈打码 | 麒跃科技 一.什么是Three.js? Three.js 是一个基于 JavaScript 的 3D 图形库,用于在网页浏览器中创建和渲染交互式 3D 内容。它基于 WebGL࿰…...
Redis远程链接应用案例
1.配置文件设置 打开配置文件redis.windows.conf,配置以下内容: 1.bind 0.0.0.0(设置所有IP可访问) 2.requirepass 1234.com(密码设置) 3.protected-mode no(远程可访问) 2.防火…...
STM32 定时器TIM
定时器基础知识 定时器就是用来定时的机器,是存在于STM32单片机中的一个外设。STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM6、TIM7),如下图所示: STM32F1…...
基于大模型的急性化脓性阑尾炎全程诊疗预测与方案研究
目录 一、引言 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目标与方法 二、大模型技术原理与应用基础 2.1 大模型概述 2.2 相关技术原理 2.3 数据收集与预处理 三、术前风险预测与准备 3.1 病情评估指标分析 3.2 大模型预测方法与结果 3.3 术前准备方案 四、…...
第一个 servlet请求
文章目录 前端后端前后端 产生 联系 前端 后端 package com.yanyu;import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse;import java.io.I…...
XLSX.utils.sheet_to_json设置了blankrows:true,但无法获取到开头的空白行
在用sheetJs的XLSX库做导入,遇到一个bug。如果开头行是空白行的话,调用sheet_to_json转数组获得的数据也是没有包含空白行的。这样会导致在设置对应的起始行时,解析数据不生效。 目前是直接跳过了开头的两行空白行 正确应该获得一下数据 问…...
python一款简单的数据库同步dts小实现
一、实现说明 在数据开发与运维场景中,数据库同步是一项基础且高频的需求。无论是开发环境与生产环境的数据镜像,还是多数据库之间的数据分发,都需要可靠的同步工具。本文将基于 Python 和pymysql库,实现一个轻量级数据库同步工具…...
误触网络重置,笔记本电脑wifi连接不上解决方法(Win10,Win11通用)
笔记本电脑连接不上网,有人说网络重置按钮可以解决,结果把wifi图标都给搞没了,只剩飞行模式,解决方法(错误码39),罪魁祸首就是这个网络重置,一下连网络都检测不到了 那么没有网络怎…...
markdown-it-katex 安装和配置指南
markdown-it-katex 是一个用于 Markdown-it 的插件,旨在通过 KaTeX 库在 Markdown 文档中添加数学公式支持。KaTeX 是一个快速渲染数学公式的库,相比于 MathJax,它在性能上有显著优势。 步骤 1: 安装 Markdown-it 首先,你需要安装…...
开源财务软件:企业财务数字化转型的有力工具
在当今数字化时代,企业财务数字化转型已成为必然趋势。随着业务的不断拓展和复杂化,企业对财务软件的需求也在日益增长。然而,传统商业财务软件往往伴随着高昂的授权费用和有限的定制化能力,这让许多企业,尤其是中小企…...
大模型——Suna集成浏览器操作与数据分析的智能代理
大模型——Suna集成浏览器操作与数据分析的智能代理 Suna 是 Kortix AI 开发的一个开源通用 AI 代理,托管在 GitHub 上,基于 Apache 2.0 许可证,允许用户免费下载、修改和自托管。它通过自然语言对话帮助用户完成复杂任务,如网页浏览、文件管理、数据抓取和网站部署。Suna…...
QT中的事件及其属性
Qt中的事件是对操作系统提供的事件机制进行封装,Qt中的信号槽就是对事件机制的进一步封装 但是特殊情况下,如对于没有提供信号的用户操作,就需要通过重写事件处理的形式,来手动处理事件的响应逻辑 常见的Qt事件: 常见事…...
flutter 选择图片 用九宫格显示图片,右上角X删除选择图片,点击查看图片放大缩小,在多张图片可以左右滑动查看图片
flutter 选择图片 用九宫格显示图片,右上角X删除选择图片,点击查看图片放大缩小,在多张图片可以左右滑动查看图片 ************ 暂无压缩图片功能 ********* 显示图片 — import dart:io;import package:flutter/material.dart; import pa…...
机器学习day2-seaborn绘图练习
1.使用tips数据集,创建一个展示不同时间段(午餐/晚餐)账单总额分布的箱线图 import seaborn as sns import matplotlib.pyplot as plt import pandas as pd import numpy as np# 设置主题 sns.set_theme(style"darkgrid")# 设置中文 plt.rcParams[font.s…...
如何优雅地解决AI生成内容粘贴到Word排版混乱的问题?
随着AI工具的广泛应用,越来越多人开始使用AI辅助撰写论文、报告或博客。然而,当我们直接将AI生成的文本复制到Word文档中时,常常会遇到排版混乱、格式异常的问题。这是因为大部分AI输出时默认使用了Markdown格式,而Word对Markdown…...
设计一个食品种类表
需求:设计一个食品种类表,注意食品种类有多层,比如面食下面,面条、方便面,面条下有干面、湿面等 一、食品种类表结构设计(food_category) CREATE TABLE food_category (category_id INT IDENT…...
Haply MinVerse触觉3D 鼠标—沉浸式数字操作,助力 3D 设计与仿真
在2025年CES展上,Haply MinVerse触觉3D鼠标凭借创新交互方式引发关注。这款设备为用户与数字环境的互动带来新维度,操作虚拟物体时能感受真实触觉反馈。 三维交互与触觉反馈 MinVerse 突破传统鼠标二维限制,增加第三运动轴,实现真…...
神经网络预测评估机制:损失函数详解
文章目录 一、引言二、损失函数的引入三、回顾预测算法四、损失函数的形式五、成本函数六、损失函数的定义与作用七、损失函数的重要性注释思维导图 一、引言 在上一篇文章中,我们了解到神经网络可通过逻辑回归等算法对输入进行预测。而判断预测结果是否准确至关重要…...
PHP实现 Apple ID 登录的服务端验证指南
在 iOS 应用中启用 “通过 Apple 登录”(Sign In with Apple)后,客户端会获取一个 身份令牌(identity token)。该令牌是一个JWT(JSON Web Token),需要由服务端验证其真实性和完整性&…...
一、linux系统启动过程操作记录
一、linux系统启动过程 经历: 上电–>uboot–>加载内核–>挂载根文件系统–>执行应用程序 uboot等效bootloader,启动过程进行了 跳转到固定的位置执行相应的代码 初始化硬件设备,如:cpu初始化 ,看门狗&a…...
【首款Armv9开源芯片“星睿“O6测评】SVE2指令集介绍与测试
SVE2指令集介绍与测试 一、什么是SVE2 在Neon架构扩展(其指令集向量长度固定为128位)的基础上,Arm设计了可伸缩向量扩展(Scalable vector extension, SVE)。SVE是一种新的单指令多数据(SIMD&am…...
获取电脑mac地址
Windows 系统 方法1:通过命令提示符 1. 按下 `Win + R`,输入 `cmd` 后按回车,打开命令提示符。 2. 输入以下命令并按回车:...
AI核心技术与应用场景的深度解析
AI核心技术与应用场景的深度解析 在互联网大厂Java求职者的面试中,经常会被问到关于AI核心技术与应用场景的问题。本文通过一个故事场景来展示这些问题的实际解决方案。 第一轮提问 面试官:马架构,欢迎来到我们公司的面试现场。请问您对AI…...
练习普通话,声音细柔和
《繁星》 我爱月夜,但我也爱星天。从前在家乡七八月 的夜晚,在庭院里纳凉的时候,我最爱看天上密密 麻麻的繁星。望着星天,我就会忘记一切,仿佛回 到了母亲的怀里似的。 三年前在南京我住的地方,有…...
Linux进程详细解析
1.操作系统 概念 任何计算机系统都包含⼀个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括: • 内核(进程管理,内存管理,文件管理,驱动管理) • 其他程序(…...
Linux执行脚本报错
执行脚本报错:./startup.sh -bash: ./startup.sh: /bin/bash^M: bad interpreter: No such file or directory ./startup.sh -bash: ./startup.sh: /bin/bash^M: bad interpreter: No such file or directory可能的原因: 文件开头格式问题:…...
C++学习:六个月从基础到就业——模板编程:类模板
C学习:六个月从基础到就业——模板编程:类模板 本文是我C学习之旅系列的第三十三篇技术文章,也是第二阶段"C进阶特性"的第十一篇,主要介绍C中的类模板编程。查看完整系列目录了解更多内容。 目录 引言类模板的基本语法…...