手写简易的SSM框架
整体结构
注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
/**
* 给加了@Component注解的类都让Spring来管理
*/
public @interface Component {
String value(); //组件名称
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
String value() default "";
}
@Target({ElementType.FIELD}) //作用目标 属性
@Retention(RetentionPolicy.RUNTIME)
public @interface Qualifier { //对象的注入
String value(); //beanName bean在工厂容器中的名称
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Query {
String value();//sql语句 查询
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Repository { //dao层
String value();
}
@Target({ElementType.TYPE,ElementType.METHOD}) //作用在类和方法上
@Retention(RetentionPolicy.RUNTIME)
/**
* 请求映射
*/
public @interface RequestMapping {
String value();//请求地址
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
String value();
}
@Target({ElementType.FIELD}) //作用目标 属性
@Retention(RetentionPolicy.RUNTIME)
public @interface StringValue {
String value(); //给String类型的属性加注解
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Update {
String value();//sql语句 增删改
}
@Controller
@RequestMapping("/goods") //请求地址
public class GoodsController {
@Qualifier("goodsService")
private GoodsService goodsService;
@RequestMapping("/remove")
public void remove(HttpServletRequest request, HttpServletResponse response){
goodsService.remove(request.getParameter("id"));
System.out.println("移除商品信息");
}
@RequestMapping("/add")
public void add(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("添加商品信息"+request.getParameter("name"));
response.getWriter().write("hello"+request.getParameter("name"));
}
@RequestMapping("/modify")
public void modify(HttpServletRequest request, HttpServletResponse response){
System.out.println("修改商品信息");
}
@RequestMapping("/list")
public void list(HttpServletRequest request, HttpServletResponse response){
List<Map<String,Object>> mapList=goodsService.list();
System.out.println(mapList);
}
}
@Controller()
public class MemberController {
@Qualifier("memberService")
private MemberService memberService01;
@StringValue("05190120")
private String vipNumber;
public void add(){
memberService01.add();
}
}
@Repository("goodsDao")
public interface GoodsDao {
@Update("delete from goods where id=?")
Integer delete(String id);
@Query("select * from goods")
List<Map<String,Object>> selectAll();
}
@Repository("memberDao")
public interface MemberDao {
void insert();
void delete();
}
@Service("goodsService")
public class GoodsService {
@Qualifier("goodsDao")
private GoodsDao goodsDao;
@Qualifier("memberDao")
private MemberDao memberDao;
public void remove(String id){
goodsDao.delete(id);
}
public List<Map<String, Object>> list() {
return goodsDao.selectAll();
}
}
@Service("memberService")
public class MemberService {
@Qualifier("memberDao")
private MemberDao memberDao;
public void add(){
memberDao.insert();
}
}
public class Dom4jUtil {
private static SAXReader saxReader=new SAXReader();
private Dom4jUtil(){
}
public static Element getRootElement(String classPathFileName){
try {
Document document = saxReader.read(Dom4jUtil.class.getClassLoader().getResourceAsStream(classPathFileName));
return document.getRootElement();
} catch (DocumentException e) {
e.printStackTrace();
}
return null;
}
}
public class JdbcUtils {
static DruidDataSource dataSource;
static {
try {
Properties prop=new Properties();
prop.load(JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"));
dataSource= (DruidDataSource) DruidDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
e.printStackTrace();
}
}
public static QueryRunner getQueryRunner(){
return new QueryRunner(dataSource);
}
}
public class ContextLoadListener implements ServletContextListener {
/**
* Tomcat启动时执行
* 在tomcat启动时加载(初始化)容器,其实就是创建容器中的对象
* @param sce
*/
public List<String> allClassNameList=new ArrayList<>();
public Map<String,Object> beanFactory=new HashMap<>();
//映射
public Map<String, Method> handlerMapping=new HashMap<>();
@Override
public void contextInitialized(ServletContextEvent sce) {
//1.扫描包(由使用者来配置)
//读入需要扫描的包名
Properties properties=new Properties();
try {
properties.load(DispatcherServlet.class.getClassLoader().getResourceAsStream("application.properties"));
} catch (IOException e) {
e.printStackTrace();
}
String basePackageName = properties.getProperty("scan-package");
//把包名转换为classPath路径
String basePackagePath=basePackageName.replaceAll("\\.","/");
//扫描指定包下面的所有的类
doScan(basePackagePath);
//2.判断我们刚才扫描出来的类哪些加了@Component,@Controller,@Service,@Repository,把添加了这些注解的类创建对象,加入到Bean的工厂中
for (String className : allClassNameList) {
try {
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(Component.class)) {//类上面是否加了Component注解
String beanName = clazz.getAnnotation(Component.class).value(); //getAnnotation()方法,返回该元素的指定类型的注解
beanFactory.put(beanName, clazz.newInstance()); //newInstance()方法来创建对象,使用类加载机制
}
if (clazz.isAnnotationPresent(Controller.class)) {
String beanName = clazz.getAnnotation(Controller.class).value();
if ("".equals(beanName)) {
char[] simpleNameArray = clazz.getSimpleName().toCharArray();
simpleNameArray[0] += 32;
beanName = new String(simpleNameArray);
}
beanFactory.put(beanName, clazz.newInstance());
}
if (clazz.isAnnotationPresent(Service.class)) {
String beanName = clazz.getAnnotation(Service.class).value();
beanFactory.put(beanName, clazz.newInstance());
}
if (clazz.isAnnotationPresent(Repository.class)) {
String beanName = clazz.getAnnotation(Repository.class).value();
Object obj=Proxy.newProxyInstance(ContextLoadListener.class.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.isAnnotationPresent(Query.class)){
//查询操作
String sql = method.getAnnotation(Query.class).value();
List<Map<String, Object>> mapList = JdbcUtils.getQueryRunner().query(sql, new MapListHandler());
return mapList;
}
if(method.isAnnotationPresent(Update.class)){
//增删改操作
String sql = method.getAnnotation(Update.class).value();
int update = JdbcUtils.getQueryRunner().update(sql,args);
return update;
}
return null;
}
});
beanFactory.put(beanName, obj);
}
}catch (ClassNotFoundException e){
e.printStackTrace();
}catch (InstantiationException e){
e.printStackTrace();
}catch (IllegalAccessException e){
e.printStackTrace();
}
}
//3.依赖注入
beanFactory.forEach((beanName,obj)->{
Field[] declaredFields = obj.getClass().getDeclaredFields();//getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和protected,但是不包括父类的声明字段
for (Field declaredField : declaredFields) {
try{
declaredField.setAccessible(true);//强吻 对私有的访问和赋值
//注入的是普通的String类型的value值
if(declaredField.isAnnotationPresent(StringValue.class)){
declaredField.set(obj,declaredField.getAnnotation(StringValue.class).value());
}
//注入的是对象
if(declaredField.isAnnotationPresent(Qualifier.class)){
String bName = declaredField.getAnnotation(Qualifier.class).value();
Object o= beanFactory.get(bName);
declaredField.set(obj,o);
}
}catch (IllegalAccessException e){
e.printStackTrace();
}
}
});
//4.解析包含@Controller注解的类里面的方法,看哪些方法上面有@RequestMapping
beanFactory.forEach((beanName,obj)->{
if (obj.getClass().isAnnotationPresent(Controller.class)) {
String baseUrl="";
//解析Controller上面有无@RequestMapping
if(obj.getClass().isAnnotationPresent(RequestMapping.class)){
baseUrl = obj.getClass().getAnnotation(RequestMapping.class).value();
}
Method[] declaredMethods = obj.getClass().getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (declaredMethod.isAnnotationPresent(RequestMapping.class)) {
String url = declaredMethod.getAnnotation(RequestMapping.class).value();
String allUrl=((baseUrl+url).trim()).replaceAll("//","/");
handlerMapping.put(allUrl,declaredMethod);
}
}
}
});
sce.getServletContext().setAttribute("applicationContext",beanFactory);
sce.getServletContext().setAttribute("handlerMapping",handlerMapping);
}
/**
* 扫描指定的包下面的所有类
* @param basePackagePath 扫描路径
*/
public void doScan(String basePackagePath){
//获取classPath路径在硬盘中的url
URL url=DispatcherServlet.class.getClassLoader().getResource(basePackagePath);
//从url中获取文件对象(绝对路径)
File basePackageFile = new File(url.getFile());
for (File file : basePackageFile.listFiles()) {
if(file.isDirectory()){
doScan(basePackagePath+"/"+file.getName());//递归调用
}else{
allClassNameList.add(basePackagePath.replaceAll("/","\\.")+"."+file.getName().replace(".class",""));
}
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {}
}
/**
* 1.接收客户端的请求
* 2.分发请求
*/
public class DispatcherServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Map applicationContext = (Map) getServletContext().getAttribute("applicationContext");
Map handlerMapping = (Map) getServletContext().getAttribute("handlerMapping");
System.out.println(handlerMapping);
String[] split = req.getRequestURI().split("/");
String baseUrl="/"+split[1];
String actionUrl="/"+split[2];
String url=baseUrl+actionUrl;
Method method= (Method) handlerMapping.get(url);
try {
method.setAccessible(true);
//调用具体的处理请求的方法
method.invoke(applicationContext.get(split[1]+"Controller"),req,resp);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
//application.properties文件
scan-package=com.zll.goods
//xml文件
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<bean name="memberController" class="com.zll.goods.controller.MemberController">
<properties>
<property name="memberService01" bean="memberService"></property>
<property name="vipNumber" value="01200519"></property>
</properties>
</bean>
<bean name="goodsController" class="com.zll.goods.controller.GoodsController">
<properties>
<property name="goodsService" bean="goodsService"></property>
</properties>
</bean>
<bean name="goodsService" class="com.zll.goods.service.GoodsService">
<properties>
<property name="goodsDao" bean="goodsDao"></property>
<property name="memberDao" bean="memberDao"></property>
</properties>
</bean>
<bean name="memberService" class="com.zll.goods.service.MemberService"></bean>
<bean name="memberDao" class="com.zll.goods.dao.MemberDao"></bean>
<bean name="goodsDao" class="com.zll.goods.dao.GoodsDao"></bean>
</beans>
//db.properties
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/bigdata06?serverTimezone=Asia/Shanghai
username=root
password=1234
initialSize=5